Ejemplo n.º 1
0
    def do_genpatch(self, argv):
        """
    genpatch -- generate a patch from a pending or submitted changelist

    px genpatch [<changelist#>]

        Generate a patch (i.e. can later be used as input for the
        'patch' program) for a given changelist number. If no change
        number is given then a patch for the 'default' changelist is
        generated. The patch is printed on stdout.

        Files opened for 'add', 'delete' or 'branch' are inlined such
        that application with 'patch' will create or delete the intended
        files.
        """
        #TODO:
        #   - Would an optional [<files> ...] argument be useful or is
        #     that overkill? E.g. 'p4 genpatch ./...' (I think that that
        #     would be very useful.
        #   - Could add '-f' option to only warn on 'out of sync'.
        #   - Could add '-d<flag>' option to control to diff format.
        #     Context and unified allowed.
        #   - Handling binary files that cannot be diff'd
        #   - Option to be able to control the base dir so the patch -p#
        #     number can be controlled. Dunno what form that should
        #     take.

        # Process options.
        diffFormat = 'u'
        if diffFormat == 'u':
            prefixes = ('---', '+++')
        elif diffFormat == 'c':
            prefixes = ('***', '---')

        # Process args.
        if not argv[1:]:
            change = 'default'
        elif len(argv[1:]) == 1:
            change = argv[1]
            try:
                change = int(change)
            except ValueError:  
                # Stupidly, p4win's new Tool %c interpolation will use
                # "Default", on which the normal p4.exe client will die.
                change = change.lower()
                if change != 'default':
                    sys.stderr.write("Invalid changelist number '%s'.\n"\
                                     % change)
                    return 1
        else:
            sys.stderr.write("Usage: genpatch [<changelist#>]\n")
            sys.stderr.write("Missing/wrong number of arguments.\n")
            return 1

        # Validate the given change number.
        p4 = p4lib.P4( **p4lib.parseOptv(self.__p4optv) )
        submitted = [c['change'] for c in p4.changes(status='submitted')]
        pending = [c['change'] for c in p4.changes(status='pending')]
        if change in submitted:
            status = 'submitted'
        elif change in pending+['default']:
            status = 'pending'
        else:
            sys.stderr.write("Change %s unknown." % change)
            return 1

        # Get list of files to include in patch.
        if status == 'submitted':
            d = p4.describe(change, diffFormat='u')
            desc = d['description']
            files = d['files']
            diffs = d['diff']
        elif status == 'pending':
            files = p4.opened(change=change)
            if change == 'default':
                desc = None
            else:
                desc = p4.change(change=change)['description']
            if files:
                diffs = p4.diff([f['depotFile'] for f in files],
                                diffFormat='u')
            else:
                diffs = []

        # Make a single string from 'diffs' with appropriate delimiters
        # for the "patch" program.
        diffstr = ''
        timestamp = time.asctime()
        for diff in diffs:
            # Perforce std header, e.g.:
            #   ==== //depot/apps/px/ReadMe.txt#5 (text) ====
            # or
            #   ==== //depot/foo.doc#42 - c:\trentm\foo.doc ==== (binary)
            if diff.has_key('localFile'):
                diffstr += "==== %(depotFile)s#%(rev)s - %(localFile)s ===="\
                           % diff
                if diff['binary']:
                    diffstr += " (binary)"
                diffstr += "\n"
            else:
                diffstr += "==== %(depotFile)s#%(rev)s (%(type)s) ====\n"\
                           % diff
            # Patch header, e.g. for unified diffs:
            #   Index: apps/px/test/ToDo.txt
            #   --- apps/px/test/ToDo.txt.~1~   Fri May 31 21:17:17 2002
            #   +++ apps/px/test/ToDo.txt       Fri May 31 21:17:17 2002
            # or for context diffs:
            #   Index: apps/px/test/ToDo.txt
            #   *** apps/px/test/ToDo.txt.~1~   Fri May 31 21:26:47 2002
            #   --- apps/px/test/ToDo.txt       Fri May 31 21:26:47 2002
            fname = diff['depotFile'][len('//depot/'):]

            if diff.has_key('text'):
                diffstr += "Index: %s\n" % fname
                diffstr += "%s %s.~1~\t%s\n" % (prefixes[0], fname, timestamp)
                diffstr += "%s %s\t%s\n" % (prefixes[1], fname, timestamp)
                # The diff text.
                diffstr += ''.join(diff['text'])
                if diffstr[-1] != '\n':
                    diffstr += "\n\\ No newline at end of file\n"

        # Inline added files into the diff.
        addedfiles = [f for f in files if f['action'] in ('add', 'branch')]
        for f in addedfiles:
            # May have to get file type from 'p4 files'.
            if status == 'submitted':
                f['type'] = p4.files(f['depotFile'])[0]['type']
            # Skip file if it is binary.
            if f['type'].startswith('binary'):
                log.warn("Cannot inline '%s' because it is binary."\
                         % f['depotFile'])
                continue
            # Get the file contents.
            if status == "pending":
                # Read the file contents from disk.
                localFile = p4.where(f['depotFile'])[0]['localFile']
                if not os.path.exists(localFile):
                    continue
                lines = open(localFile, 'r').readlines()
            else:
                # Get the file contents via 'p4 print'.
                fnameRev = "%s#%s" % (f['depotFile'], f['rev'])
                lines = p4.print_(fnameRev)[0]['text'].split('\n')
                if not lines[-1]: lines = lines[:-1] # drop empty last line
                lines = [line+'\n' for line in lines]
            # Inline the file.
            diffstr += "\n==== %(depotFile)s#%(rev)s (%(type)s) ====\n" % f
            if len(lines) < 2:
                ln = ""
            else:
                ln = "," + str(len(lines))
            fname = f['depotFile'][len('//depot/'):]
            diffstr += "Index: %s\n" % fname
            diffstr += "%s %s.~1~\t%s\n" % (prefixes[0], fname, timestamp)
            diffstr += "%s %s\t%s\n" % (prefixes[1], fname, timestamp)
            diffstr += "@@ -0,0 +1%s @@\n" % ln
            diffstr += '+' + '+'.join(lines)
            if diffstr[-1] != '\n':
                diffstr += "\n\\ No newline at end of file\n"
                
        if diffstr: # std patch terminator
            diffstr += "End of Patch."

        patch = p4lib.makeForm(description=desc, files=files,
                               differences=diffstr)
        if patch: # ViM-specific hack to have it colorize patches as diffs.
            patch = "diff\n" + patch

        sys.stdout.write(patch)
Ejemplo n.º 2
0
        describe = 0
        for opt, optarg in optlist:
            if opt == '-i':
                followIntegrations = 1
            elif opt == '-l':
                longOutput = 1
            elif opt == '-m':
                max = int(optarg)
            elif opt == '-s':
                status = optarg
            elif opt == '-d':
                describe = 1

        if describe:
            # Get a list of change numbers to describe.
            p4 = p4lib.P4( **p4lib.parseOptv(self.__p4optv) )
            changes = p4.changes(args, followIntegrations=followIntegrations,
                                 longOutput=longOutput, max=max,
                                 status=status)
            changeNums = [c['change'] for c in changes]
            log.info("Changenums to describe: %s" % changeNums)

            # Describe each change.
            for num in changeNums:
                retval = self._p4run(['describe', '-du', str(num)])
                if retval:
                    raise PxError("Error running '%s': retval=%s"\
                                  % (cmd, retval))
        else:
            return self._p4run(argv)