35
35
                @param dir the fully-qualified directory to work in.
 
 
39
                self.ignored_files = [ '.bzr', '.bzrignore' ]
 
 
42
        def has_authority( self ):
 
 
43
                """Check that the directory is under this VCS's control.
 
 
46
                return os.path.exists( os.path.join( self.dir, '.bzr' ) )
 
 
49
        def expand_repo_url( self, url ):
 
 
50
                """Convert a simple hostname in to an URL that the VCS can use.
 
 
53
                return 'bzr+ssh://%s/%s/%s' % ( url, the.dir, the.repo.name )
 
 
85
101
                """Obtain some sort of revision identifier
 
89
105
                output = self.run( [ 'bzr', 'revno', '--tree' ] )
 
92
 
                buf = StringIO.StringIO( output )
 
 
108
                buf = io.StringIO( output )
 
93
109
                return buf.readline().rstrip()
 
 
108
124
                # symlink to a non-existant file)
 
109
125
                if 'kind changed' in files:
 
110
126
                        for file in files[ 'kind changed' ]:
 
111
 
                                matches = re.match( r'(.+?)[/@+]? \([^)]+\)', file )
 
 
127
                                matches = re.search( '^(.+?)[/@+]? \([^)]+\)$', file )
 
113
129
                                        raise RunTimeError(
 
114
130
                                                'failed to parse bzr kind change: %s' % file )
 
115
131
                                file = matches.group( 1 )
 
116
 
                                if the.verbose >= 2: print "removing (kind changed): " + file
 
 
132
                                if the.verbose >= 2: print("removing (kind changed): " + file)
 
117
133
                                full_file = os.path.join( self.dir, file )
 
118
134
                                if os.path.isfile( full_file ) or os.path.islink( full_file ):
 
119
135
                                        os.unlink( full_file )
 
 
132
148
                # remove unknown files
 
133
149
                if 'unknown' in files:
 
134
150
                        for file in files[ 'unknown' ]:
 
135
 
                                if the.verbose >= 2: print "removing (unknown): " + file
 
 
151
                                matches = re.search( r'^(.+?)[/@+]?$', file )
 
 
154
                                                'failed to parse bzr unknowns: %s' % file )
 
 
155
                                file = matches.group( 1 )
 
 
156
                                if the.verbose >= 2: print("removing (unknown): " + file)
 
136
157
                                full_file = os.path.join( self.dir, file )
 
137
 
                                if os.path.isfile( full_file ):
 
 
158
                                if os.path.isfile( full_file ) or os.path.islink( full_file ):
 
138
159
                                        os.unlink( full_file )
 
139
160
                                elif os.path.isdir( full_file ):
 
140
161
                                        shutil.rmtree( full_file )
 
 
199
220
                # parse output (see logic in report() in bzrlib/delta.py)
 
201
 
                buf = StringIO.StringIO( output )
 
 
222
                buf = io.StringIO( output )
 
203
224
                        if not re.search( '^[-R+ ?][K NMD!][* ] ', line ): continue
 
204
225
                        line = line.rstrip()
 
205
 
                        if the.verbose >= 2: print '  %s' % line
 
207
227
                        # renames show before and after file names
 
208
228
                        matches = re.search( '^R.. (.*?)[/@+]? => (.*?)[/@+]?$', line )
 
 
 
253
                """Get a list of any local modifications.  This method returns a list of files
 
 
259
                output = self.run( [ 'bzr', 'status', '--no-pending' ] )
 
 
262
                return self.parse_file_blocks( output )
 
232
265
        def has_changes( self ):
 
233
266
                """Check if the branch has any local modifications.
 
 
270
 
                self.run( [ 'bzr', 'commit', '-m', '' ] )
 
 
304
                        self.run( [ 'bzr', 'commit', '-m', '' ] )
 
 
305
                except self.VcsError as e:
 
 
306
                        if re.search( 'Working tree is out of date', e.output ):
 
 
307
                                raise the.program.FatalError(
 
 
308
                                        'you must update your files first.\n' +
 
 
309
                                        'Hint: see "%s update --help"' % the.program.name );
 
273
314
        def run( self, cmd ):
 
274
 
                if the.verbose >= 2: print 'exec: %s' % ' '.join( cmd )
 
 
315
                if the.verbose >= 2: print('exec: %s' % ' '.join( cmd ))
 
275
316
                p = Popen( cmd, cwd = self.dir,
 
276
317
                                   stdout = subprocess.PIPE, stderr = subprocess.STDOUT )
 
277
 
                output = p.communicate()[ 0 ]
 
 
318
                output = p.communicate()[ 0 ].decode()
 
278
319
                if p.returncode > 0:
 
279
320
                        raise self.VcsError( ' '.join( cmd[ : 2 ] ), output )
 
 
322
                        verbose_output = output.rstrip()
 
 
323
                        if len( verbose_output ):
 
 
324
                                print(re.sub( '(^|\n)', '\\1  : ', verbose_output ))
 
283
328
        def parse_file_blocks( self, output ):
 
286
 
                buf = StringIO.StringIO( output )
 
 
331
                buf = io.StringIO( output )
 
288
333
                        matches = re.search( '^([a-z ]+):$', line, re.I )