Skip to content

Commit e494ab3

Browse files
authored
Merge pull request #4 from conan-io/hotfix/new-delete
Import Conan patches
2 parents 6fb1899 + 33363f8 commit e494ab3

File tree

2 files changed

+105
-1
lines changed

2 files changed

+105
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
[![Build Status](https://travis-ci.org/conan-io/python-patch-ng.svg?branch=master)](https://travis-ci.org/conan-io/python-patch-ng)
12
[![PyPI](https://img.shields.io/pypi/v/patch-ng)](https://pypi.python.org/pypi/patch-ng)
23

34
## Patch NG (New Generation)

patch_ng.py

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,15 @@
3131
from __future__ import print_function
3232

3333
__author__ = "Conan.io <info@conan.io>"
34-
__version__ = "1.17"
34+
__version__ = "1.17.1"
3535
__license__ = "MIT"
3636
__url__ = "https://github.com/conan-io/python-patch"
3737

3838
import copy
3939
import logging
4040
import re
4141
import tempfile
42+
import codecs
4243

4344
# cStringIO doesn't support unicode in 2.5
4445
try:
@@ -225,6 +226,73 @@ def pathstrip(path, n):
225226
# --- /Utility function ---
226227

227228

229+
def decode_text(text):
230+
encodings = {codecs.BOM_UTF8: "utf_8_sig",
231+
codecs.BOM_UTF16_BE: "utf_16_be",
232+
codecs.BOM_UTF16_LE: "utf_16_le",
233+
codecs.BOM_UTF32_BE: "utf_32_be",
234+
codecs.BOM_UTF32_LE: "utf_32_le",
235+
b'\x2b\x2f\x76\x38': "utf_7",
236+
b'\x2b\x2f\x76\x39': "utf_7",
237+
b'\x2b\x2f\x76\x2b': "utf_7",
238+
b'\x2b\x2f\x76\x2f': "utf_7",
239+
b'\x2b\x2f\x76\x38\x2d': "utf_7"}
240+
for bom in sorted(encodings, key=len, reverse=True):
241+
if text.startswith(bom):
242+
try:
243+
return text[len(bom):].decode(encodings[bom])
244+
except UnicodeDecodeError:
245+
continue
246+
decoders = ["utf-8", "Windows-1252"]
247+
for decoder in decoders:
248+
try:
249+
return text.decode(decoder)
250+
except UnicodeDecodeError:
251+
continue
252+
logger.warning("can't decode %s" % str(text))
253+
return text.decode("utf-8", "ignore") # Ignore not compatible characters
254+
255+
256+
def to_file_bytes(content):
257+
if PY3K:
258+
if not isinstance(content, bytes):
259+
content = bytes(content, "utf-8")
260+
elif isinstance(content, unicode):
261+
content = content.encode("utf-8")
262+
return content
263+
264+
265+
def load(path, binary=False):
266+
""" Loads a file content """
267+
with open(path, 'rb') as handle:
268+
tmp = handle.read()
269+
return tmp if binary else decode_text(tmp)
270+
271+
272+
def save(path, content, only_if_modified=False):
273+
"""
274+
Saves a file with given content
275+
Params:
276+
path: path to write file to
277+
content: contents to save in the file
278+
only_if_modified: file won't be modified if the content hasn't changed
279+
"""
280+
try:
281+
os.makedirs(os.path.dirname(path))
282+
except Exception:
283+
pass
284+
285+
new_content = to_file_bytes(content)
286+
287+
if only_if_modified and os.path.exists(path):
288+
old_content = load(path, binary=True)
289+
if old_content == new_content:
290+
return
291+
292+
with open(path, "wb") as handle:
293+
handle.write(new_content)
294+
295+
228296
class Hunk(object):
229297
""" Parsed hunk data container (hunk starts with @@ -R +R @@) """
230298

@@ -879,11 +947,46 @@ def _strip_prefix(self, filename):
879947
return filename[2:]
880948
return filename
881949

950+
def decode_clean(self, path, prefix):
951+
path = path.decode("utf-8").replace("\\", "/")
952+
if path.startswith(prefix):
953+
path = path[2:]
954+
return path
955+
956+
def strip_path(self, path, base_path, strip=0):
957+
tokens = path.split("/")
958+
if len(tokens) > 1:
959+
tokens = tokens[strip:]
960+
path = "/".join(tokens)
961+
if base_path:
962+
path = os.path.join(base_path, path)
963+
return path
964+
# account for new and deleted files, upstream dep won't fix them
965+
966+
967+
968+
882969
def apply(self, strip=0, root=None):
883970
""" Apply parsed patch, optionally stripping leading components
884971
from file paths. `root` parameter specifies working dir.
885972
return True on success
886973
"""
974+
items = []
975+
for item in self.items:
976+
source = self.decode_clean(item.source, "a/")
977+
target = self.decode_clean(item.target, "b/")
978+
if "dev/null" in source:
979+
target = self.strip_path(target, root, strip)
980+
hunks = [s.decode("utf-8") for s in item.hunks[0].text]
981+
new_file = "".join(hunk[1:] for hunk in hunks)
982+
save(target, new_file)
983+
elif "dev/null" in target:
984+
source = self.strip_path(source, root, strip)
985+
os.unlink(source)
986+
else:
987+
items.append(item)
988+
self.items = items
989+
887990
if root:
888991
prevdir = os.getcwd()
889992
os.chdir(root)

0 commit comments

Comments
 (0)