diff --git a/.travis.yml b/.travis.yml index 71b8bb6..239708f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,25 @@ language: python python: - - "2.6" - "2.7" - - "3.3" - "3.4" - "3.5" - - "3.5-dev" # 3.5 development branch - - "nightly" # currently points to 3.6-dev - + - "3.6" + - "3.7" + - "3.7-dev" + - "3.8-dev" + +os: linux +arch: + - amd64 + - arm64 + install: - pip install coverage + - pip install pypack script: # run tests with coverage - coverage run tests/run_tests.py - coverage report -m + # test distribution packaging + - python -m pypack patch.py diff --git a/README.md b/README.md index da1f0c2..6cca3fd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ Library to parse and apply unified diffs. -[![Build Status](https://img.shields.io/travis/techtonik/python-patch.svg)](https://travis-ci.org/techtonik/python-patch) +[![Build Status](https://img.shields.io/travis/techtonik/python-patch/master)](https://travis-ci.org/techtonik/python-patch/branches) [![PyPI](https://img.shields.io/pypi/v/patch)](https://pypi.python.org/pypi/patch) ### Features diff --git a/doc/RELEASING b/doc/RELEASING index e0e4d7d..f367207 100644 --- a/doc/RELEASING +++ b/doc/RELEASING @@ -1,6 +1,7 @@ * [ ] Pack .zip archive - python ./other/pack.py patch.py + pip install pypack + python -m pypack patch.py * [ ] Write changelog diff --git a/doc/evolution-notes.txt b/doc/evolution-notes.txt index 784f5e6..7c544c2 100644 --- a/doc/evolution-notes.txt +++ b/doc/evolution-notes.txt @@ -13,6 +13,7 @@ patchset evolution 2. copy file 2. copy and rename 2. move and rename +2. remove file 3. know file attributes 3. know file mime-type diff --git a/other/pack.mainpy.tpl b/other/pack.mainpy.tpl deleted file mode 100644 index fa4b7a0..0000000 --- a/other/pack.mainpy.tpl +++ /dev/null @@ -1,4 +0,0 @@ -import sys - -import {{ module }} -sys.exit({{ module }}.main()) diff --git a/other/pack.py b/other/pack.py deleted file mode 100755 index 8ed523e..0000000 --- a/other/pack.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python -""" -Wrap Python module into executable .zip file - -Public domain work by: - anatoly techtonik -""" -import os -import sys - -def get_version(path): - '''Read version info from a file without importing it''' - for line in open(path, 'rb'): - # Decode to unicode for PY2/PY3 in a fail-safe way - line = line.decode('cp437') - if '__version__' in line: - # __version__ = "0.9" - return line.split('"')[1] - -def zipadd(archive, filename, newname): - '''Add filename to archive. `newname` is required. Otherwise - zipfile may create unsafe entries, such as "../patch.py". - Returns open ZipFile object. - ''' - import zipfile - zf = zipfile.ZipFile(archive, 'a', zipfile.ZIP_DEFLATED) - zf.write(filename, newname) - return zf - -class MiniJinja(object): - """Template engine that knows how to render {{ tag }}""" - - def __init__(self, templates='.'): - """templates - template path""" - import re - import sys - self.PY3K = sys.version_info[0] == 3 - - self.path = templates + '/' - self.tag = re.compile('{{ *(?P\w+) *}}') - - def render(self, template, vardict=None, **kwargs): - """returns unicode str""" - data = vardict or {} - data.update(kwargs) - - def lookup(match): - return data[match.group('tag')] - - tpl = open(self.path + template).read() - if not self.PY3K: - return unicode(self.tag.sub(lookup, tpl)) - else: - return self.tag.sub(lookup, tpl) - -# --- - -BASE = os.path.abspath(os.path.dirname(__file__)) - -if __name__ == '__main__': - if not sys.argv[1:]: - sys.exit("usage: pack.py ") - - modpath = sys.argv[1] - modname = os.path.basename(modpath)[:-3] # also strip extension - version = get_version(modpath) - if version == None: - sys.exit("error: no __version__ specifier found in %s" % modpath) - packname = modname + "-" + version + ".zip" - print("[*] Packing %s into %s" % (modpath, packname)) - if os.path.exists(packname): - os.remove(packname) - zf = zipadd(packname, modpath, os.path.basename(modpath)) - print("[*] Making %s executable" % (packname)) - # http://techtonik.rainforce.org/2015/01/shipping-python-tools-in-executable-zip.html - text = MiniJinja(BASE).render('pack.mainpy.tpl', module=modname) - zf.writestr('__main__.py', text) - print("[*] Making %s installable" % (packname)) - text2 = MiniJinja(BASE).render('pack.setuppy.tpl', module=modname, version=version) - zf.writestr('setup.py', text2) - print("[*] Making %s uploadable to PyPI" % (packname)) - zf.writestr('PKG-INFO', '') - zf.close() - diff --git a/other/pack.setuppy.tpl b/other/pack.setuppy.tpl deleted file mode 100644 index b82c24d..0000000 --- a/other/pack.setuppy.tpl +++ /dev/null @@ -1,18 +0,0 @@ -from distutils.core import setup - -setup( - name='{{ module }}', - version='{{ version }}', - author='anatoly techtonik ', - url='https://github.com/techtonik/python-patch/', - - description='Patch utility to apply unified diffs', - license='MIT', - - py_modules=['{{ module }}'], - - classifiers=[ - 'Classifier: Programming Language :: Python :: 2', - 'Classifier: Programming Language :: Python :: 3', - ], -) diff --git a/patch.py b/patch.py index 45c5a48..4775d70 100755 --- a/patch.py +++ b/patch.py @@ -7,13 +7,13 @@ Copyright (c) 2008-2016 anatoly techtonik Available under the terms of MIT license - https://github.com/techtonik/python-patch/ - """ from __future__ import print_function __author__ = "anatoly techtonik " __version__ = "1.16" +__license__ = "MIT" +__url__ = "https://github.com/techtonik/python-patch" import copy import logging @@ -337,7 +337,7 @@ def lineno(self): hunkparsed = False # state after successfully parsed hunk # regexp to match start of hunk, used groups - 1,3,4,6 - re_hunk_start = re.compile(b"^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@") + re_hunk_start = re.compile(br"^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@") self.errors = 0 # temp buffers for header and filenames info @@ -516,7 +516,7 @@ def lineno(self): filenames = False headscan = True else: - re_filename = b"^\+\+\+ ([^\t]+)" + re_filename = br"^\+\+\+ ([^\t]+)" match = re.match(re_filename, line) if not match: warning("skipping invalid patch - no target filename at line %d" % (lineno+1)) @@ -542,7 +542,7 @@ def lineno(self): continue if hunkhead: - match = re.match(b"^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@(.*)", line) + match = re.match(br"^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@(.*)", line) if not match: if not p.hunks: warning("skipping invalid patch with no hunks for file %s" % p.source)