This file is indexed.

/usr/share/pyshared/qctlib/vcs/mtn.py is in qct 1.7-3.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# Monotone VCS back-end code for qct
#
# Copyright 2006 Steve Borho
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.

# Usage Notes:
#
# User must specify a get_passphrase() in their monotonerc in order for
# this back-end to commit files.

from qctlib.utils import runProgram, findInSystemPath, scanDiffOutput, isBinary
from tempfile import mkstemp
from stat import *
import os

class qctVcsMtn:
    def initRepo(self, argv):
        '''Initialize your revision control system, open repository'''

        self.mtn_exe = 'mtn'
        output = runProgram([self.mtn_exe, 'ls', 'unknown'], expectedexits=[0,1])
        if output.startswith('mtn: misuse: workspace required'):
            print "No Monotone repository found"
            return -1

        # Verify we have a valid repository
        self.stateNames = { 'M' : 'modified',
                'R' : 'removed',
                '!' : 'missing',
                '?' : 'unknown' }

        self.capList = [
                'ignore',      # VCS supports ignore masks (addIgnoreMask)
                'rename',      # VCS supports revisioned renames (fileMoveDetected)
                'progressbar'] # back-end supports a progress bar

        return 0

    def capabilities(self):
        '''Return a list of optional capabilities supported by this VCS'''
        return self.capList

    def generateParentFile(self, workingFile):
        '''The GUI needs this file's parent revision in place so the user
           can select individual changes for commit (basically a revert)
        '''
        runProgram([self.mtn_exe, 'revert', workingFile])

    def addIgnoreMask(self, newIgnoreMask):
        '''The user has provided a new ignoreMask to be added to revision control
           Requires 'ignore' capability.
        '''
        # (probably too simple) Glob-to-Regexp
        regexp = '^'
        for char in newIgnoreMask:
            if char == '*':
                regexp += '.*'
            elif char == '.':
                regexp += '\.'
            else:
                regexp += char
        regexp += '$'

        if not os.path.exists('.mtn-ignore'):
            print 'No ignore file found, unable to add %s' % regexp
            return

        try:
            f = open('.mtn-ignore', 'a')
            f.write(regexp)
            f.write('\n')
            f.close()
            print "Added regexp '%s' to ignore mask" % regexp
        except IOError, e:
            print "Unable to add '%s' to ignore mask" % regexp
            print e
        pass

    def fileMoveDetected(self, origFileName, newFileName):
        '''User has associated an unknown file with a missing file, describing
           a move/rename which occurred outside of revision control
           Requires 'rename' capability
        '''
        runProgram([self.mtn_exe, 'rename', origFileName, newFileName])

    def getLogTemplate(self):
        '''Request default log message template from VCS'''
        return ''

    def getAutoSelectTypes(self):
        '''Return annotations of file types which should be automatically
           selected when a new commit is started'''
        return ['A', 'M', 'R', '>']

    def dirtyCache(self, fileName):
        '''The GUI would like us to forget cached data for this file'''
        if self.wdDiffCache.has_key(fileName):
            del self.wdDiffCache[fileName]

    def scanFiles(self, showIgnored, pb = None):
        '''Request scan for all commitable files from VCS, with optional
           progress bar
        '''
        # Called at startup, when 'Refresh' button is pressed, or when showIgnored toggled.
        self.wdDiffCache = {}

        inventory = runProgram([self.mtn_exe, 'automate', 'inventory']).split(os.linesep)[:-1]
        if pb: pb.setValue(1)

        self.fileState = {}
        itemList = []
        renameSrc = {}
        renameDest = {}
        listedFiles = []
        for line in inventory:
            state = line[0:3]
            srcRename = line[4]
            destRename = line[6]
            fileName = line[8:]

            if state == '   ':
                # Skip unchanged files
                continue

            self.fileState[fileName] = state

            if srcRename != '0':
                renameSrc[srcRename] = fileName
            if destRename != '0':
                renameDest[destRename] = fileName

            if state[2] == 'I':      # Ignored by lua-hook
                if showIgnored:
                    itemList.append('I ' + fileName)
                    listedFiles.append(fileName)
            elif state[2] == 'P':    # patched (modified)
                itemList.append('M ' + fileName)
                listedFiles.append(fileName)
            elif state[2] == 'U':    # Unknown
                if state[0] == 'D':  # Dropped
                    itemList.append('R ' + fileName)
                    listedFiles.append(fileName)
                else:
                    itemList.append('? ' + fileName)
                    listedFiles.append(fileName)
            elif state[2] == 'M':    # Missing
                itemList.append('! ' + fileName)
                listedFiles.append(fileName)
            elif state[2] == ' ':
                if state[1] == 'A':  # Added
                    itemList.append('A ' + fileName)
                    listedFiles.append(fileName)
                elif state[0] == 'D':
                    itemList.append('R ' + fileName)
                    listedFiles.append(fileName)
            elif state[0] == 'R' or state[1] == 'R':
                pass
            else:
                print '%s [%s] is uncharacterized!' % (fileName, state)

        if pb: pb.setValue(2)

        # Find rename pairs
        self.renameTarget = {}
        for k in renameSrc.keys():
            src = renameSrc[k]
            tgt = renameDest[k]
            self.renameTarget[src] = tgt
            if src not in listedFiles:
                itemList.append('> ' + src)
                listedFiles.append(src)

        if pb: pb.setValue(3)

        return itemList


    def __getWorkingDirChanges(self, fileName, type):
        if self.wdDiffCache.has_key(fileName):
            return self.wdDiffCache[fileName]

        # For symlinks, we return the link data
        if type not in ['R', '!', '>']:
            lmode = os.lstat(fileName)[ST_MODE]
            if S_ISLNK(lmode):
                text = "Symlink: %s -> %s" % (fileName, os.readlink(fileName))
                self.wdDiffCache[fileName] = text
                return text

        # For revisioned files, we use hg diff
        if type in ['A', 'M', 'R']:
            text = runProgram([self.mtn_exe, 'diff', fileName])
            self.wdDiffCache[fileName] = text
            return text

        # For unrevisioned files, we return file contents
        if type in ['?', 'I']:
            if os.path.isdir(fileName):
                text = " <Unrevisioned Directory>"
                fnames = os.listdir(fileName)
                text += os.linesep + ' ' + '\n '.join(fnames)
            elif isBinary(fileName):
                text = " <Binary File>"
            else:
                f = open(fileName)
                text = f.read()
                f.close()
            self.wdDiffCache[fileName] = text
            return text

        if type == '>':
            target = self.renameTarget[fileName]
            text = 'Rename event: %s [%s] -> %s [%s]' % (fileName, self.fileState[fileName],
                            target, self.fileState[target])
            self.wdDiffCache[fileName] = text
            return text

        # For missing files, we use mtn cat
        if type == '!':
            if self.fileState[fileName][1] == 'A':
                text = " <Missing file was never revisioned>"
                self.wdDiffCache[fileName] = text
                return text
            text = runProgram([self.mtn_exe, 'cat', fileName])
            if not text: text = " <empty file>"
            elif '\0' in text: text = " <Binary File of %d KBytes>" % (len(text) / 1024)
            self.wdDiffCache[fileName] = text
            return text
        else:
            return "Unknown file type " + type


    def getFileStatus(self, itemName):
        '''Request file deltas from VCS'''

        type = itemName[0]
        fileName = itemName[2:]
        text = self.__getWorkingDirChanges(fileName, type)

        # Useful shorthand vars.  Leading lines beginning with % are treated as RTF
        bFileName = '%' + '<b>%s</b> [%s]' % (fileName, self.fileState[fileName])
        noteLineSep = os.linesep + '%'

        if type == 'A':
            note = bFileName + " has been added to revision control, but has never been commited."
            return note + os.linesep + text
        elif type == 'M':
            note = bFileName + " has been modified in your working directory."
            return note + os.linesep + text
        elif type == '?':
            note = bFileName + " is not currently tracked. If commited, it will be added to revision control."
            return note + os.linesep + "= Unrevisioned File Contents" + os.linesep + text
        elif type == 'I':
            note = bFileName + " is usually ignored, but will be added to revision control if commited"
            return note + os.linesep + text
        elif type == 'R':
            note = bFileName + " has been marked for deletion, but has not yet been commited"
            note += noteLineSep + "The file can be recovered by reverting it to it's last revisioned state."
            return note + os.linesep + "= Removed File Diffs" + os.linesep + text
        elif type == '!':
            note = bFileName + " was tracked but is now missing. If commited, it will be marked as dropped."
            note += noteLineSep + "The file can be recovered by reverting it to it's last revisioned state."
            return note + os.linesep + "= Contents of Missing File" + os.linesep + text
        elif type == '>':
            return text
        else:
            return "Unknown file type " + type


    def commitFiles(self, selectedFileList, logMsgText):
        '''Commit selected files'''
        # Files in list are annotated (A, M, etc) so this function can
        # mark files for add or delete as necessary before instigating the commit.
        commitFileNames = []
        addFileList = []
        removeFileList = []
        for f in selectedFileList:
            type = f[0]
            fileName = f[2:]
            commitFileNames.append(fileName)
            if type in ['?', 'I']: addFileList.append(fileName)
            elif type == '!': removeFileList.append(fileName)

        if addFileList:
            runProgram([self.mtn_exe, 'add'] + addFileList)
            print "Added %d file(s) to revision control: %s" % (len(addFileList), ', '.join(addFileList))

        if removeFileList:
            runProgram([self.mtn_exe, 'drop'] + removeFileList)
            print "Removed %d file(s) from revision control: %s" % (len(removeFileList), ', '.join(removeFileList))

        (fd, filename) = mkstemp()
        file = os.fdopen(fd, "w+b")
        file.write(logMsgText)
        file.close()
        runProgram([self.mtn_exe, 'commit', '--message-file', filename] + commitFileNames)
        print "%d file(s) commited: %s" % (len(commitFileNames), ', '.join(commitFileNames))

    def addFiles(self, selectedFileList):
        '''Add selected files to version control'''
        runProgram([self.mtn_exe, 'add'] + selectedFileList)

    def revertFiles(self, selectedFileList):
        '''Revert selected files to last revisioned state'''
        revertFileNames = []
        for f in selectedFileList:
            type = f[0]
            fileName = f[2:]
            if type in ['R', '!', 'M']:
                prevState = self.stateNames[type]
                print "%s recovered to last revisioned state (was %s)" % (fileName, prevState)
                revertFileNames.append(fileName)
            elif type == 'A':
                print "%s removed from revision control (was added)" % fileName
                revertFileNames.append(fileName)
            elif type == '>':
                runProgram([self.mtn_exe, 'revert', fileName])
                targetName = self.renameTarget[ fileName ]
                os.unlink(targetName)
                print "Rename of %s reverted, %s removed" % (fileName, targetName)
            else:
                print "File %s not reverted" % fileName

        if revertFileNames:
            runProgram([self.mtn_exe, 'revert'] + revertFileNames)

# vim: tw=120