server/virtualenv/res/lib/patch.py
author ymh <ymh.work@gmail.com>
Fri, 29 May 2015 02:22:11 +0200
changeset 3 fc0f3e398166
permissions -rw-r--r--
Creation of Django server project
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
3
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
     1
""" Patch utility to apply unified diffs
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
     2
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
     3
    Brute-force line-by-line non-recursive parsing 
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
     4
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
     5
    Copyright (c) 2008-2010 anatoly techtonik
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
     6
    Available under the terms of MIT license
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
     7
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
     8
    Project home: http://code.google.com/p/python-patch/
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
     9
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    10
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    11
    $Id: patch.py 76 2010-04-08 19:10:21Z techtonik $
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    12
    $HeadURL: https://python-patch.googlecode.com/svn/trunk/patch.py $
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    13
"""
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    14
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    15
__author__ = "techtonik.rainforce.org"
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    16
__version__ = "10.04"
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    17
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    18
import copy
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    19
import logging
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    20
import re
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    21
# cStringIO doesn't support unicode in 2.5
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    22
from StringIO import StringIO
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    23
from logging import debug, info, warning
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    24
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    25
from os.path import exists, isfile, abspath
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    26
from os import unlink
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    27
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    28
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    29
#------------------------------------------------
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    30
# Logging is controlled by "python_patch" logger
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    31
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    32
debugmode = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    33
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    34
logger = logging.getLogger("python_patch")
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    35
loghandler = logging.StreamHandler()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    36
logger.addHandler(loghandler)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    37
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    38
debug = logger.debug
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    39
info = logger.info
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    40
warning = logger.warning
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    41
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    42
#: disable library logging by default
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    43
logger.setLevel(logging.CRITICAL)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    44
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    45
#------------------------------------------------
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    46
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    47
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    48
def fromfile(filename):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    49
  """ Parse patch file and return Patch() object
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    50
  """
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    51
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    52
  info("reading patch from file %s" % filename)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    53
  fp = open(filename, "rb")
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    54
  patch = Patch(fp)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    55
  fp.close()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    56
  return patch
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    57
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    58
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    59
def fromstring(s):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    60
  """ Parse text string and return Patch() object
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    61
  """
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    62
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    63
  return Patch(
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    64
           StringIO.StringIO(s)    
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    65
         )
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    66
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    67
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    68
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    69
class HunkInfo(object):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    70
  """ Parsed hunk data container (hunk starts with @@ -R +R @@) """
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    71
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    72
  def __init__(self):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    73
    self.startsrc=None #: line count starts with 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    74
    self.linessrc=None
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    75
    self.starttgt=None
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    76
    self.linestgt=None
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    77
    self.invalid=False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    78
    self.text=[]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    79
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    80
  def copy(self):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    81
    return copy.copy(self)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    82
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    83
#  def apply(self, estream):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    84
#    """ write hunk data into enumerable stream
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    85
#        return strings one by one until hunk is
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    86
#        over
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    87
#
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    88
#        enumerable stream are tuples (lineno, line)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    89
#        where lineno starts with 0
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    90
#    """
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    91
#    pass
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    92
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    93
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    94
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    95
class Patch(object):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    96
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    97
  def __init__(self, stream=None):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    98
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
    99
    # define Patch data members
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   100
    # table with a row for every source file
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   101
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   102
    #: list of source filenames
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   103
    self.source=None
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   104
    self.target=None
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   105
    #: list of lists of hunks
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   106
    self.hunks=None
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   107
    #: file endings statistics for every hunk
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   108
    self.hunkends=None
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   109
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   110
    if stream:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   111
      self.parse(stream)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   112
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   113
  def copy(self):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   114
    return copy.copy(self)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   115
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   116
  def parse(self, stream):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   117
    """ parse unified diff """
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   118
    self.source = []
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   119
    self.target = []
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   120
    self.hunks = []
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   121
    self.hunkends = []
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   122
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   123
    # define possible file regions that will direct the parser flow
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   124
    header = False    # comments before the patch body
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   125
    filenames = False # lines starting with --- and +++
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   126
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   127
    hunkhead = False  # @@ -R +R @@ sequence
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   128
    hunkbody = False  #
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   129
    hunkskip = False  # skipping invalid hunk mode
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   130
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   131
    header = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   132
    lineends = dict(lf=0, crlf=0, cr=0)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   133
    nextfileno = 0
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   134
    nexthunkno = 0    #: even if index starts with 0 user messages number hunks from 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   135
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   136
    # hunkinfo holds parsed values, hunkactual - calculated
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   137
    hunkinfo = HunkInfo()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   138
    hunkactual = dict(linessrc=None, linestgt=None)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   139
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   140
    fe = enumerate(stream)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   141
    for lineno, line in fe:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   142
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   143
      # analyze state
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   144
      if header and line.startswith("--- "):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   145
        header = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   146
        # switch to filenames state
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   147
        filenames = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   148
      #: skip hunkskip and hunkbody code until you read definition of hunkhead
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   149
      if hunkbody:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   150
        # process line first
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   151
        if re.match(r"^[- \+\\]", line):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   152
            # gather stats about line endings
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   153
            if line.endswith("\r\n"):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   154
              self.hunkends[nextfileno-1]["crlf"] += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   155
            elif line.endswith("\n"):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   156
              self.hunkends[nextfileno-1]["lf"] += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   157
            elif line.endswith("\r"):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   158
              self.hunkends[nextfileno-1]["cr"] += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   159
              
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   160
            if line.startswith("-"):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   161
              hunkactual["linessrc"] += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   162
            elif line.startswith("+"):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   163
              hunkactual["linestgt"] += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   164
            elif not line.startswith("\\"):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   165
              hunkactual["linessrc"] += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   166
              hunkactual["linestgt"] += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   167
            hunkinfo.text.append(line)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   168
            # todo: handle \ No newline cases
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   169
        else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   170
            warning("invalid hunk no.%d at %d for target file %s" % (nexthunkno, lineno+1, self.target[nextfileno-1]))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   171
            # add hunk status node
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   172
            self.hunks[nextfileno-1].append(hunkinfo.copy())
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   173
            self.hunks[nextfileno-1][nexthunkno-1]["invalid"] = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   174
            # switch to hunkskip state
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   175
            hunkbody = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   176
            hunkskip = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   177
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   178
        # check exit conditions
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   179
        if hunkactual["linessrc"] > hunkinfo.linessrc or hunkactual["linestgt"] > hunkinfo.linestgt:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   180
            warning("extra hunk no.%d lines at %d for target %s" % (nexthunkno, lineno+1, self.target[nextfileno-1]))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   181
            # add hunk status node
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   182
            self.hunks[nextfileno-1].append(hunkinfo.copy())
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   183
            self.hunks[nextfileno-1][nexthunkno-1]["invalid"] = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   184
            # switch to hunkskip state
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   185
            hunkbody = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   186
            hunkskip = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   187
        elif hunkinfo.linessrc == hunkactual["linessrc"] and hunkinfo.linestgt == hunkactual["linestgt"]:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   188
            self.hunks[nextfileno-1].append(hunkinfo.copy())
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   189
            # switch to hunkskip state
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   190
            hunkbody = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   191
            hunkskip = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   192
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   193
            # detect mixed window/unix line ends
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   194
            ends = self.hunkends[nextfileno-1]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   195
            if ((ends["cr"]!=0) + (ends["crlf"]!=0) + (ends["lf"]!=0)) > 1:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   196
              warning("inconsistent line ends in patch hunks for %s" % self.source[nextfileno-1])
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   197
            if debugmode:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   198
              debuglines = dict(ends)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   199
              debuglines.update(file=self.target[nextfileno-1], hunk=nexthunkno)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   200
              debug("crlf: %(crlf)d  lf: %(lf)d  cr: %(cr)d\t - file: %(file)s hunk: %(hunk)d" % debuglines)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   201
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   202
      if hunkskip:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   203
        match = re.match("^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))?", line)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   204
        if match:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   205
          # switch to hunkhead state
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   206
          hunkskip = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   207
          hunkhead = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   208
        elif line.startswith("--- "):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   209
          # switch to filenames state
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   210
          hunkskip = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   211
          filenames = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   212
          if debugmode and len(self.source) > 0:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   213
            debug("- %2d hunks for %s" % (len(self.hunks[nextfileno-1]), self.source[nextfileno-1]))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   214
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   215
      if filenames:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   216
        if line.startswith("--- "):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   217
          if nextfileno in self.source:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   218
            warning("skipping invalid patch for %s" % self.source[nextfileno])
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   219
            del self.source[nextfileno]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   220
            # double source filename line is encountered
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   221
            # attempt to restart from this second line
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   222
          re_filename = "^--- ([^\t]+)"
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   223
          match = re.match(re_filename, line)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   224
          # todo: support spaces in filenames
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   225
          if match:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   226
            self.source.append(match.group(1).strip())
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   227
          else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   228
            warning("skipping invalid filename at line %d" % lineno)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   229
            # switch back to header state
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   230
            filenames = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   231
            header = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   232
        elif not line.startswith("+++ "):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   233
          if nextfileno in self.source:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   234
            warning("skipping invalid patch with no target for %s" % self.source[nextfileno])
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   235
            del self.source[nextfileno]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   236
          else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   237
            # this should be unreachable
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   238
            warning("skipping invalid target patch")
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   239
          filenames = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   240
          header = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   241
        else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   242
          if nextfileno in self.target:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   243
            warning("skipping invalid patch - double target at line %d" % lineno)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   244
            del self.source[nextfileno]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   245
            del self.target[nextfileno]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   246
            nextfileno -= 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   247
            # double target filename line is encountered
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   248
            # switch back to header state
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   249
            filenames = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   250
            header = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   251
          else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   252
            re_filename = "^\+\+\+ ([^\t]+)"
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   253
            match = re.match(re_filename, line)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   254
            if not match:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   255
              warning("skipping invalid patch - no target filename at line %d" % lineno)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   256
              # switch back to header state
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   257
              filenames = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   258
              header = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   259
            else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   260
              self.target.append(match.group(1).strip())
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   261
              nextfileno += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   262
              # switch to hunkhead state
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   263
              filenames = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   264
              hunkhead = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   265
              nexthunkno = 0
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   266
              self.hunks.append([])
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   267
              self.hunkends.append(lineends.copy())
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   268
              continue
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   269
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   270
      if hunkhead:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   271
        match = re.match("^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))?", line)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   272
        if not match:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   273
          if nextfileno-1 not in self.hunks:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   274
            warning("skipping invalid patch with no hunks for file %s" % self.target[nextfileno-1])
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   275
            # switch to header state
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   276
            hunkhead = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   277
            header = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   278
            continue
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   279
          else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   280
            # switch to header state
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   281
            hunkhead = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   282
            header = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   283
        else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   284
          hunkinfo.startsrc = int(match.group(1))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   285
          hunkinfo.linessrc = 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   286
          if match.group(3): hunkinfo.linessrc = int(match.group(3))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   287
          hunkinfo.starttgt = int(match.group(4))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   288
          hunkinfo.linestgt = 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   289
          if match.group(6): hunkinfo.linestgt = int(match.group(6))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   290
          hunkinfo.invalid = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   291
          hunkinfo.text = []
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   292
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   293
          hunkactual["linessrc"] = hunkactual["linestgt"] = 0
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   294
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   295
          # switch to hunkbody state
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   296
          hunkhead = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   297
          hunkbody = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   298
          nexthunkno += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   299
          continue
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   300
    else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   301
      if not hunkskip:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   302
        warning("patch file incomplete - %s" % filename)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   303
        # sys.exit(?)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   304
      else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   305
        # duplicated message when an eof is reached
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   306
        if debugmode and len(self.source) > 0:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   307
            debug("- %2d hunks for %s" % (len(self.hunks[nextfileno-1]), self.source[nextfileno-1]))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   308
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   309
    info("total files: %d  total hunks: %d" % (len(self.source), sum(len(hset) for hset in self.hunks)))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   310
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   311
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   312
  def apply(self):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   313
    """ apply parsed patch """
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   314
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   315
    total = len(self.source)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   316
    for fileno, filename in enumerate(self.source):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   317
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   318
      f2patch = filename
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   319
      if not exists(f2patch):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   320
        f2patch = self.target[fileno]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   321
        if not exists(f2patch):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   322
          warning("source/target file does not exist\n--- %s\n+++ %s" % (filename, f2patch))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   323
          continue
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   324
      if not isfile(f2patch):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   325
        warning("not a file - %s" % f2patch)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   326
        continue
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   327
      filename = f2patch
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   328
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   329
      info("processing %d/%d:\t %s" % (fileno+1, total, filename))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   330
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   331
      # validate before patching
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   332
      f2fp = open(filename)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   333
      hunkno = 0
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   334
      hunk = self.hunks[fileno][hunkno]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   335
      hunkfind = []
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   336
      hunkreplace = []
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   337
      validhunks = 0
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   338
      canpatch = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   339
      for lineno, line in enumerate(f2fp):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   340
        if lineno+1 < hunk.startsrc:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   341
          continue
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   342
        elif lineno+1 == hunk.startsrc:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   343
          hunkfind = [x[1:].rstrip("\r\n") for x in hunk.text if x[0] in " -"]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   344
          hunkreplace = [x[1:].rstrip("\r\n") for x in hunk.text if x[0] in " +"]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   345
          #pprint(hunkreplace)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   346
          hunklineno = 0
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   347
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   348
          # todo \ No newline at end of file
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   349
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   350
        # check hunks in source file
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   351
        if lineno+1 < hunk.startsrc+len(hunkfind)-1:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   352
          if line.rstrip("\r\n") == hunkfind[hunklineno]:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   353
            hunklineno+=1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   354
          else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   355
            debug("hunk no.%d doesn't match source file %s" % (hunkno+1, filename))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   356
            # file may be already patched, but we will check other hunks anyway
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   357
            hunkno += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   358
            if hunkno < len(self.hunks[fileno]):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   359
              hunk = self.hunks[fileno][hunkno]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   360
              continue
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   361
            else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   362
              break
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   363
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   364
        # check if processed line is the last line
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   365
        if lineno+1 == hunk.startsrc+len(hunkfind)-1:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   366
          debug("file %s hunk no.%d -- is ready to be patched" % (filename, hunkno+1))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   367
          hunkno+=1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   368
          validhunks+=1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   369
          if hunkno < len(self.hunks[fileno]):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   370
            hunk = self.hunks[fileno][hunkno]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   371
          else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   372
            if validhunks == len(self.hunks[fileno]):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   373
              # patch file
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   374
              canpatch = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   375
              break
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   376
      else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   377
        if hunkno < len(self.hunks[fileno]):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   378
          warning("premature end of source file %s at hunk %d" % (filename, hunkno+1))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   379
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   380
      f2fp.close()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   381
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   382
      if validhunks < len(self.hunks[fileno]):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   383
        if self._match_file_hunks(filename, self.hunks[fileno]):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   384
          warning("already patched  %s" % filename)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   385
        else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   386
          warning("source file is different - %s" % filename)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   387
      if canpatch:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   388
        backupname = filename+".orig"
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   389
        if exists(backupname):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   390
          warning("can't backup original file to %s - aborting" % backupname)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   391
        else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   392
          import shutil
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   393
          shutil.move(filename, backupname)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   394
          if self.write_hunks(backupname, filename, self.hunks[fileno]):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   395
            warning("successfully patched %s" % filename)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   396
            unlink(backupname)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   397
          else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   398
            warning("error patching file %s" % filename)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   399
            shutil.copy(filename, filename+".invalid")
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   400
            warning("invalid version is saved to %s" % filename+".invalid")
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   401
            # todo: proper rejects
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   402
            shutil.move(backupname, filename)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   403
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   404
    # todo: check for premature eof
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   405
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   406
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   407
  def can_patch(self, filename):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   408
    """ Check if specified filename can be patched. Returns None if file can
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   409
    not be found among source filenames. False if patch can not be applied
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   410
    clearly. True otherwise.
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   411
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   412
    :returns: True, False or None
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   413
    """
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   414
    idx = self._get_file_idx(filename, source=True)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   415
    if idx == None:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   416
      return None
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   417
    return self._match_file_hunks(filename, self.hunks[idx])
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   418
    
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   419
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   420
  def _match_file_hunks(self, filepath, hunks):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   421
    matched = True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   422
    fp = open(abspath(filepath))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   423
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   424
    class NoMatch(Exception):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   425
      pass
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   426
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   427
    lineno = 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   428
    line = fp.readline()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   429
    hno = None
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   430
    try:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   431
      for hno, h in enumerate(hunks):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   432
        # skip to first line of the hunk
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   433
        while lineno < h.starttgt:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   434
          if not len(line): # eof
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   435
            debug("check failed - premature eof before hunk: %d" % (hno+1))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   436
            raise NoMatch
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   437
          line = fp.readline()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   438
          lineno += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   439
        for hline in h.text:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   440
          if hline.startswith("-"):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   441
            continue
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   442
          if not len(line):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   443
            debug("check failed - premature eof on hunk: %d" % (hno+1))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   444
            # todo: \ No newline at the end of file
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   445
            raise NoMatch
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   446
          if line.rstrip("\r\n") != hline[1:].rstrip("\r\n"):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   447
            debug("file is not patched - failed hunk: %d" % (hno+1))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   448
            raise NoMatch
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   449
          line = fp.readline()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   450
          lineno += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   451
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   452
    except NoMatch:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   453
      matched = False
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   454
      # todo: display failed hunk, i.e. expected/found
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   455
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   456
    fp.close()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   457
    return matched
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   458
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   459
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   460
  def patch_stream(self, instream, hunks):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   461
    """ Generator that yields stream patched with hunks iterable
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   462
    
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   463
        Converts lineends in hunk lines to the best suitable format
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   464
        autodetected from input
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   465
    """
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   466
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   467
    # todo: At the moment substituted lineends may not be the same
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   468
    #       at the start and at the end of patching. Also issue a
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   469
    #       warning/throw about mixed lineends (is it really needed?)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   470
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   471
    hunks = iter(hunks)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   472
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   473
    srclineno = 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   474
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   475
    lineends = {'\n':0, '\r\n':0, '\r':0}
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   476
    def get_line():
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   477
      """
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   478
      local utility function - return line from source stream
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   479
      collecting line end statistics on the way
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   480
      """
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   481
      line = instream.readline()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   482
        # 'U' mode works only with text files
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   483
      if line.endswith("\r\n"):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   484
        lineends["\r\n"] += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   485
      elif line.endswith("\n"):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   486
        lineends["\n"] += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   487
      elif line.endswith("\r"):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   488
        lineends["\r"] += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   489
      return line
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   490
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   491
    for hno, h in enumerate(hunks):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   492
      debug("hunk %d" % (hno+1))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   493
      # skip to line just before hunk starts
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   494
      while srclineno < h.startsrc:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   495
        yield get_line()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   496
        srclineno += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   497
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   498
      for hline in h.text:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   499
        # todo: check \ No newline at the end of file
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   500
        if hline.startswith("-") or hline.startswith("\\"):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   501
          get_line()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   502
          srclineno += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   503
          continue
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   504
        else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   505
          if not hline.startswith("+"):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   506
            get_line()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   507
            srclineno += 1
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   508
          line2write = hline[1:]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   509
          # detect if line ends are consistent in source file
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   510
          if sum([bool(lineends[x]) for x in lineends]) == 1:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   511
            newline = [x for x in lineends if lineends[x] != 0][0]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   512
            yield line2write.rstrip("\r\n")+newline
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   513
          else: # newlines are mixed
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   514
            yield line2write
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   515
     
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   516
    for line in instream:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   517
      yield line
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   518
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   519
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   520
  def write_hunks(self, srcname, tgtname, hunks):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   521
    src = open(srcname, "rb")
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   522
    tgt = open(tgtname, "wb")
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   523
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   524
    debug("processing target file %s" % tgtname)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   525
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   526
    tgt.writelines(self.patch_stream(src, hunks))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   527
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   528
    tgt.close()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   529
    src.close()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   530
    return True
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   531
  
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   532
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   533
  def _get_file_idx(self, filename, source=None):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   534
    """ Detect index of given filename within patch.
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   535
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   536
        :param filename:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   537
        :param source: search filename among sources (True),
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   538
                       targets (False), or both (None)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   539
        :returns: int or None
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   540
    """
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   541
    filename = abspath(filename)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   542
    if source == True or source == None:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   543
      for i,fnm in enumerate(self.source):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   544
        if filename == abspath(fnm):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   545
          return i  
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   546
    if source == False or source == None:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   547
      for i,fnm in enumerate(self.target):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   548
        if filename == abspath(fnm):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   549
          return i  
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   550
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   551
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   552
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   553
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   554
from optparse import OptionParser
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   555
from os.path import exists
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   556
import sys
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   557
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   558
if __name__ == "__main__":
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   559
  opt = OptionParser(usage="%prog [options] unipatch-file", version="python-patch %s" % __version__)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   560
  opt.add_option("--debug", action="store_true", dest="debugmode", help="debug mode")
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   561
  (options, args) = opt.parse_args()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   562
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   563
  if not args:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   564
    opt.print_version()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   565
    opt.print_help()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   566
    sys.exit()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   567
  debugmode = options.debugmode
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   568
  patchfile = args[0]
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   569
  if not exists(patchfile) or not isfile(patchfile):
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   570
    sys.exit("patch file does not exist - %s" % patchfile)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   571
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   572
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   573
  if debugmode:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   574
    loglevel = logging.DEBUG
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   575
    logformat = "%(levelname)8s %(message)s"
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   576
  else:
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   577
    loglevel = logging.INFO
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   578
    logformat = "%(message)s"
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   579
  logger.setLevel(loglevel)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   580
  loghandler.setFormatter(logging.Formatter(logformat))
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   581
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   582
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   583
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   584
  patch = fromfile(patchfile)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   585
  #pprint(patch)
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   586
  patch.apply()
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   587
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   588
  # todo: document and test line ends handling logic - patch.py detects proper line-endings
fc0f3e398166 Creation of Django server project
ymh <ymh.work@gmail.com>
parents:
diff changeset
   589
  #       for inserted hunks and issues a warning if patched file has incosistent line ends