/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/vcs/bzr.py

  • Committer: Tim Marston
  • Date: 2014-02-12 21:51:08 UTC
  • Revision ID: tim@ed.am-20140212215108-stk5z0nlvgpi4oa8
added bzr as a vcs backend; finished init command; implemented deployment

Show diffs side-by-side

added added

removed removed

21
21
 
22
22
import subprocess, os, re, shutil
23
23
from subprocess import Popen
 
24
import stdhome.the as the
24
25
import StringIO
25
 
from vcs import Vcs
26
 
from stdhome import the
27
 
 
28
 
 
29
 
class BzrVcs( Vcs ):
 
26
 
 
27
 
 
28
class VcsBzr:
30
29
 
31
30
 
32
31
        def __init__( self, dir ):
45
44
                os.mkdir( self.dir )
46
45
 
47
46
                # bzr init
48
 
                try:
49
 
                        self.run( [ 'bzr', 'init', '.' ] )
50
 
                except self.VcsError as e:
 
47
                p = Popen( [ 'bzr', 'init', '.' ], cwd = self.dir,
 
48
                                   stdout = subprocess.PIPE, stderr = subprocess.STDOUT )
 
49
                output = p.communicate()[ 0 ]
 
50
                if p.returncode > 0:
51
51
 
52
52
                        # attempt to clean-up dir
53
53
                        try:
55
55
                        except OSError:
56
56
                                pass
57
57
 
58
 
                        raise
 
58
                        raise the.program.FatalError( 'bzr init failed', output )
59
59
 
60
60
 
61
61
        def checkout( self, url ):
68
68
                os.mkdir( self.dir )
69
69
 
70
70
                # bzr co
71
 
                try:
72
 
                        self.run( [ 'bzr', 'checkout', url, '.' ] )
73
 
                except self.VcsError as e:
 
71
                p = Popen( [ 'bzr', 'co', url, '.' ], cwd = self.dir,
 
72
                                   stdout = subprocess.PIPE, stderr = subprocess.STDOUT )
 
73
                output = p.communicate()[ 0 ]
 
74
                if p.returncode > 0:
74
75
 
75
76
                        # attempt to clean-up dir
76
77
                        try:
78
79
                        except OSError:
79
80
                                pass
80
81
 
81
 
                        raise
82
 
 
83
 
 
84
 
        def get_revno( self ):
85
 
                """Obtain some sort of revision identifier
86
 
                """
87
 
 
88
 
                # bzr revert
89
 
                output = self.run( [ 'bzr', 'revno', '--tree' ] )
90
 
 
91
 
                # parse revno
92
 
                buf = StringIO.StringIO( output )
93
 
                return buf.readline().rstrip()
94
 
 
95
 
 
96
 
        def revert( self, revno = None ):
 
82
                        raise the.program.FatalError( 'bzr checkout failed', output )
 
83
 
 
84
 
 
85
        def revert( self ):
97
86
                """Revert the branch so that there are no outstanding changes or unknown files.
98
 
                If a revno is supplied, then the repository is reverted to that
99
 
                revision.
100
87
                """
101
88
 
102
89
                # bzr revert
103
 
                self.run( [ 'bzr', 'revert', '--no-backup' ] )
 
90
                p = Popen( [ 'bzr', 'revert', '--no-backup' ], cwd = self.dir,
 
91
                                   stdout = subprocess.PIPE, stderr = subprocess.STDOUT )
 
92
                output = p.communicate()[ 0 ]
 
93
                if p.returncode > 0:
 
94
                        raise the.program.FatalError( 'bzr revert failed', output )
104
95
 
105
96
                # bzr st
106
 
                output = self.run( [ 'bzr', 'status' ] )
 
97
                p = Popen( [ 'bzr', 'st' ], cwd = self.dir,
 
98
                                   stdout = subprocess.PIPE, stderr = subprocess.STDOUT )
 
99
                output = p.communicate()[ 0 ]
 
100
                if p.returncode > 0:
 
101
                        raise the.program.FatalError( 'bzr status failed', output )
107
102
                files = self.parse_file_blocks( output )
108
103
 
109
104
                # remove unknown files
117
112
                                else:
118
113
                                        raise RuntimeError( 'exotic file in repo: %s' % file )
119
114
 
120
 
                # if a revision identifyer has been given, update to that
121
 
                if revno is not None:
122
 
 
123
 
                        # bzr update
124
 
                        self.run( [ 'bzr', 'update', '-r', revno ] )
125
 
 
126
115
 
127
116
        def update( self ):
128
 
                """Update the branch, pulling down any upstream changes and merging them.  This
129
 
                method returns a list of the files that were modified as part of this
130
 
                operation.
 
117
                """Update the branch, pulling down any upstream changes and merging them.
131
118
                """
132
119
 
133
 
#               WARNING: the following might cause bzr to ask for your ssh password more than
134
 
#               once during an update!!!
135
 
#
136
 
#               # get revno
137
 
#               revno = self.get_revno()
138
 
#
139
 
#               # update to current revision (pull in history without updating tree)
140
 
#               self.run( [ 'bzr', 'update', '-r', revno ] )
141
 
#
142
 
#               # get log output
143
 
#               next_revno = str( int( revno ) + 1 )
144
 
#               output = self.run( [ 'bzr', 'log', '-r', next_revno + '..' ] )
145
 
#
146
 
#               # parse output
147
 
#               keep_files = list()
148
 
#               buf = StringIO.StringIO( output )
149
 
#               in_message = False
150
 
#               for line in buf:
151
 
#                       line = line.rstrip( '\n' )
152
 
#                       if line.lower() == 'message:':
153
 
#                               in_message = True
154
 
#                       elif in_message:
155
 
#                               if line[ : 2 ] != '  ':
156
 
#                                       in_message = False
157
 
#                               else:
158
 
#                                       line = line[ 2 : ]
159
 
#
160
 
#                                       # process directives
161
 
#                                       if line[ : 6 ].lower() == 'keep: ':
162
 
#                                               file = line[ 6 : ]
163
 
#                                               if file in rename_files: file = rename_files[ file ]
164
 
#                                               keep_files.append( file )
165
 
#                                       elif line[ : 8 ].lower() == 'rename: ':
166
 
#                                               rename_from = line[ 8 : ]
167
 
#                                       elif line[ : 4 ].lower() == 'to: ':
168
 
#                                               if rename_from in rename_files:
169
 
#                                                       rename_from = rename_files[ rename_from ]
170
 
#                                               rename_files[ line[ 4 : ] ] = rename_from
171
 
 
172
 
                # bzr update properly
173
 
                output = self.run( [ 'bzr', 'update' ] )
174
 
 
175
 
                # parse output (see logic in report() in bzrlib/delta.py)
176
 
                files = list()
177
 
                buf = StringIO.StringIO( output )
178
 
                for line in buf:
179
 
                        if not re.search( '^[-R+ ?][K NMD!][* ] ', line ): continue
180
 
                        line = line.rstrip()
181
 
                        if the.verbose > 1: print '  %s' % line
182
 
 
183
 
                        # renames show before and after file names
184
 
                        matches = re.search( '^R.. (.*?)[/@+]? => (.*?)[/@+]?$', line )
185
 
                        if matches:
186
 
                                files.append( matches.group( 1 ) )
187
 
                                files.append( matches.group( 2 ) )
188
 
                                continue
189
 
 
190
 
                        # kind changes shows the same name twice
191
 
                        matches = re.search( '^.K. (.*?)[/@+]? => (.*?)[/@+]?$', line )
192
 
                        if matches:
193
 
                                files.append( matches.group( 1 ) )
194
 
                                continue
195
 
 
196
 
                        # other entries have only one filename
197
 
                        matches = re.search( '^... (.*?)[/@+]?$', line )
198
 
                        if matches:
199
 
                                files.append( matches.group( 1 ) )
200
 
                                continue
201
 
 
202
 
                        raise RuntimeError(
203
 
                                'failed to parse bzr update output line:\n%' % line )
204
 
 
205
 
                return files
 
120
                # bzr update
 
121
                p = Popen( [ 'bzr', 'update' ], cwd = self.dir,
 
122
                                   stdout = subprocess.PIPE, stderr = subprocess.STDOUT )
 
123
                output = p.communicate()[ 0 ]
 
124
                if p.returncode > 0:
 
125
                        raise the.program.FatalError( 'bzr update failed', output )
206
126
 
207
127
 
208
128
        def has_changes( self ):
210
130
                """
211
131
 
212
132
                # bzr status
213
 
                output = self.run( [ 'bzr', 'status', '--no-pending' ] )
214
 
 
215
 
                # parse output
 
133
                p = Popen( [ 'bzr', 'status', '--no-pending' ], cwd = self.dir,
 
134
                                   stdout = subprocess.PIPE, stderr = subprocess.STDOUT )
 
135
                output = p.communicate()[ 0 ]
 
136
                if p.returncode > 0:
 
137
                        raise the.program.FatalError( 'bzr status failed', output )
216
138
                files = self.parse_file_blocks( output )
217
139
                return True if len( files ) else False
218
140
 
222
144
                """
223
145
 
224
146
                # bzr status
225
 
                output = self.run( [ 'bzr', 'status', '--no-pending' ] )
226
 
 
227
 
                # parse output
 
147
                p = Popen( [ 'bzr', 'status', '--no-pending' ], cwd = self.dir,
 
148
                                   stdout = subprocess.PIPE, stderr = subprocess.STDOUT )
 
149
                output = p.communicate()[ 0 ]
 
150
                if p.returncode > 0:
 
151
                        raise the.program.FatalError( 'bzr status failed', output )
228
152
                files = self.parse_file_blocks( output )
229
153
                return files['conflicts'] if 'conflicts' in files else None
230
154
 
231
155
 
232
 
        def run( self, cmd ):
233
 
                if the.verbose > 1: print 'exec: %s' % ' '.join( cmd )
234
 
                p = Popen( cmd, cwd = self.dir,
235
 
                                   stdout = subprocess.PIPE, stderr = subprocess.STDOUT )
236
 
                output = p.communicate()[ 0 ]
237
 
                if p.returncode > 0:
238
 
                        raise self.VcsError( ' '.join( cmd[ : 2 ] ), output )
239
 
                return output
240
 
 
241
 
 
242
156
        def parse_file_blocks( self, output ):
243
157
                res = dict()
244
158
                current = None