Skip to content

Commit

Permalink
py26 compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
casperdcl committed Oct 30, 2016
1 parent 4ba54d6 commit b882682
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 13 deletions.
25 changes: 13 additions & 12 deletions pymake/_pymake.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,19 @@
"""
from __future__ import absolute_import
# import compatibility functions and utilities
from ._utils import ConfigParser, StringIO
from ._utils import ConfigParser, StringIO, shlex
import io
import re
from subprocess import check_call
import shlex


__author__ = {"github.com/": ["casperdcl", "lrq3000"]}
__all__ = ['PymakeTypeError', 'PymakeKeyError',
'parse_makefile_aliases', 'execute_makefile_commands']


RE_MAKE_CMD = re.compile('^\t(@\+?)(make)?', flags=re.M)
RE_MACRO_DEF = re.compile(r"^(\S+)\s*\:?\=\s*(.*?)$", flags=re.M)
RE_MACRO = re.compile(r"\$\(\s*\S+\s*\)", flags=re.M)
RE_MAKE_CMD = re.compile('^\t(@\+?)(make)?')
RE_MACRO_DEF = re.compile(r"^(\S+)\s*\:?\=\s*(.*?)$")
RE_MACRO = re.compile(r"\$\(\s*\S+\s*\)")


class PymakeTypeError(TypeError):
Expand All @@ -42,19 +40,22 @@ def parse_makefile_aliases(filepath):

# -- Parsing the Makefile using ConfigParser
# Adding a fake section to make the Makefile a valid Ini file
ini_str = '[root]\n'
ini_lines = ['[root]']
with io.open(filepath, mode='r') as fd:
ini_str = ini_str + RE_MAKE_CMD.sub('\t', fd.read())
ini_lines.extend(RE_MAKE_CMD.sub('\t', i) for i in fd.readlines())

# Substitute macros
macros = dict(RE_MACRO_DEF.findall(ini_str))
macros = dict(found for l in ini_lines
for found in RE_MACRO_DEF.findall(l) if found)
ini_str = '\n'.join(ini_lines)
# allow finite amount of nesting
for _ in range(99):
for (m, expr) in getattr(macros, 'iteritems', macros.items)():
ini_str = re.sub(r"\$\(" + m + "\)", expr, ini_str, flags=re.M)
if not RE_MACRO.match(ini_str):
ini_str = re.sub(r"\$\(" + m + "\)", expr, ini_str)
if not RE_MACRO.search(ini_str):
# Strip macro definitions for rest of parsing
ini_str = RE_MACRO_DEF.sub("", ini_str)
ini_str = '\n'.join(l for l in ini_str.splitlines()
if not RE_MACRO_DEF.search(l))
break
else:
raise PymakeKeyError("No substitution for macros: " +
Expand Down
38 changes: 37 additions & 1 deletion pymake/_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
__all__ = ["ConfigParser", "StringIO", "_sh"]
import sys

__all__ = ["ConfigParser", "StringIO", "_sh", "shlex"]

if True: # pragma: no cover
try:
Expand All @@ -18,6 +20,40 @@
except NameError:
_unicode = str

if sys.version_info >= (2, 7): # pragma: no cover
import shlex
else: # pragma: no cover
import re

class shlex(object):
""" Emulate built-in shlex.split using re """
# tokens may be surrounded by unescaped quote pairs
RE_TOKEN = re.compile(r'(?<!\\)(?P<q>[\'"])(.*?)(?<!\\)(?P=q)')
RE_WTSPC = re.compile(r'\s+')
# unescaped hash (designates a comment when unquoted)
RE_CMMNT = re.compile(r'(.*?)(?<!\\)#')

@classmethod
def split(cls, cmd, comments=True):
toks = cls.RE_TOKEN.split(cmd)
res = []
quoted = False
for t in toks:
if quoted:
if t:
res.append(t)
quoted = False
elif t in '\'"':
quoted = True
elif t:
c = cls.RE_CMMNT.split(t)
uncom = (c[0] or c[1]).strip()
if uncom:
res.extend(cls.RE_WTSPC.split(uncom))
if len(c) > 1:
break # rest is comment
return res


def _sh(*cmd, **kwargs):
import subprocess
Expand Down

0 comments on commit b882682

Please sign in to comment.