diff options
author | MCApollo <34170230+MCApollo@users.noreply.github.com> | 2019-04-20 20:49:46 -0500 |
---|---|---|
committer | MCApollo <34170230+MCApollo@users.noreply.github.com> | 2019-04-23 20:18:47 -0500 |
commit | 12335518ab39608d58370c85ff9f5384ad2aa5f7 (patch) | |
tree | 352d81f2a2de3f1252af732080ec0fde38c13b4d /util/.marauder | |
parent | a2b26ad12d4fa12f0273645caf4be6d0b8b71e7c (diff) |
Ported in the homebrew-marauder for a hacky update/import system.
TODO: Maybe add a license & fix up messy code.
Diffstat (limited to 'util/.marauder')
-rw-r--r-- | util/.marauder/marauder/__init__.py | 4 | ||||
-rw-r--r-- | util/.marauder/marauder/install.py | 200 | ||||
-rw-r--r-- | util/.marauder/marauder/parser.py | 277 | ||||
-rw-r--r-- | util/.marauder/marauder/version.py | 40 |
4 files changed, 521 insertions, 0 deletions
diff --git a/util/.marauder/marauder/__init__.py b/util/.marauder/marauder/__init__.py new file mode 100644 index 000000000..379afe39b --- /dev/null +++ b/util/.marauder/marauder/__init__.py @@ -0,0 +1,4 @@ +__version__ = '2.0' +from .parser import parse +from .version import version +from .install import makesh
\ No newline at end of file diff --git a/util/.marauder/marauder/install.py b/util/.marauder/marauder/install.py new file mode 100644 index 000000000..3c7b20405 --- /dev/null +++ b/util/.marauder/marauder/install.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python3 +import re +import csv +import sys + + +# FIXME 18 Errors - 18/02 + +def _variable(word): + + def ENV(): + # Easier to parse & handle this way. + ENV.cc = '${PKG_TARG}-clang' + ENV.ld = '${PKG_TARG}-ld' + ENV.cxx = '${PKG_TARG}-clang++' + ENV.cflags = '${CFLAGS}' + ENV.ldflags = '${LDFLAGS}' + ENV.cxxflags = '${CXXFLAGS}' + ENV.cppflags = '${CPPFLAGS}' + ENV() + + prefix = '${PKG_TAPF}' + man = '${PKG_TAPF}' + '/share/man' + pkgshare = '${PKG_TAPF}' + '/share' + lib = '${PKG_TAPF}' + '/lib' + share = '${PKG_TAPF}' + '/share' + + sysconfig = '/etc' + bin = '${PKG_TAPF}' + 'bin' + + # include = '$SDK' + '/usr/include' + + b = ['ENV', 'prefix', 'man', 'pkgshare', 'lib', 'include'] + + w = ''.join(word) + try: + if not any([x for x in b if w.startswith(x)]): + return False # Prevent code execution + word = eval(w) + except NameError: + return False + except AttributeError: +# print(f'WARNING: {w} needs to be defined.', file=sys.stderr) + # raise + return False + + return word + + + +def _system(): + """ Handles strings like: system "make", "install """ + + def _configure(): + nonlocal l + banned = [#'--disable-debug', + '--prefix=', + '--man=', + '--mandir=', + '--localstatedir=', + '--sysconfdir=', + '--infodir=', + '--datadir' + '--disable-dependency-tracking', + '--disable-debug'] + regex = re.compile(f"{'|'.join(banned)}*") + track = '' + for x in l: + if not any([a for a in x.split() if regex.search(a)]): + track += f' {x}' + + l = track.strip() + try: + conf = re.search('(^.+/configure)', l).group(1) + except AttributeError: + # print("ERROR: configure - AttributeError - NoneType has no attribute 'group'", file=sys.stderr) + conf = l[0] + if conf == './configure': + l = l.replace(conf, f"pkg:configure") + else: + l = l.replace(conf, f"PKG_CONF={conf} pkg:configure") + + def _make(): + nonlocal l + l = ' '.join(l) + l = l.replace('install', 'DESTDIR=${PKG_DEST} install', 1) +# if == 'make': # if the line is just `make` +# l = l.replace('make', 'pkg:make') # Hand it to pkg:make for the args + + def _cmake(): + nonlocal l + l = ' '.join(l) + l = l.replace(r'*std_cmake_args', r'-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}') + + + l = re.sub(r'^system', '', g_line).strip() + l = list(csv.reader([l], quotechar='"', skipinitialspace=True))[0] + + # Convert #{variable} to a bash variable. + variable = [k for k, p in enumerate(l) if re.findall(r'#{(?:[A-Za-z0-9.]+)}', p)] + if variable: + for p in variable: + n = re.findall(r'#{([A-Za-z0-9.]+)}', l[p]) + k = _variable(n) + if not k: + continue # _variable() returned False for some reason. + l[p] = l[p].replace(f"#{{{''.join(n)}}}", f'{k}') + + if 'configure' in l[0]: + _configure() + elif 'cmake' in l[0]: + _cmake() + elif 'make' in l[0]: + _make() + else: + l = ' '.join(l) + + return l + + +def _inreplace(): + # TODO: inreplace |s|, let replace be a bash function, so remove any shell characters. + return -1 + +def _clean(file): + """ Cleans up input for parsing """ + file = iter(file) + + def list(): + # FIXME: 2 Formulas will error out here - ['inreplace %w[configure Makefile], for example. + nonlocal x + if re.search(r'%[A-Za-z]\[', x): + track = x + if x.endswith("]") or '].each' in x: + return track + else: + while True: + l = next(file) + track += f'{l}' + if re.search(r'^\]\.?', l): + break + track += ' ' + return track + return False + + def newlines(): + nonlocal x + if not x.endswith(','): + return False + line = x + l = x + while True: + if not line.endswith(','): + break + line = next(file) + l += f' {line}' + return l + + out = [] + for x in file: + _list = list() + if _list: + out += [_list] + else: + _newline = newlines() + if _newline: + out += [_newline] + else: + out += [x] + return out + + +def makesh(file=None): + try: + data = _clean(file) + except StopIteration: + # print(f'ERROR: parse - StopIteration - {file}', file=sys.stderr) + return None # Error + global g_line # Global line + n = [] + for g_line in data: + if g_line.endswith('if build.head?'): + continue # Doesn't support head. + elif g_line.startswith("system"): + n += [_system()] + elif g_line.startswith("mkdir"): + try: + cd = re.findall(r'\"(.+?)\"', g_line)[0] + except IndexError: + # TODO - Fix index error + # print("ERROR: parse - IndexError - cd regex failed", file=sys.stderr) + n += [g_line] + continue + n += [re.sub('do$', f'&& cd {cd}', g_line)] + elif g_line.startswith("cd"): + n += [re.sub('do$', '', g_line)] + else: + n += [g_line] + + return n diff --git a/util/.marauder/marauder/parser.py b/util/.marauder/marauder/parser.py new file mode 100644 index 000000000..1d5d2fdd1 --- /dev/null +++ b/util/.marauder/marauder/parser.py @@ -0,0 +1,277 @@ +import re +import sys + +keywords = re.compile(r"^(desc|homepage|url|mirror|bottle|patch|def|resource|depends_on|conflicts_with|__END__)") + +regex_quoted = re.compile(r'["\'](.*?)["\']') +regex_resource = re.compile(r'resource "(.*?)" do') + +def _reset(): + global result + result = { + "name": None, + "description": None, + "url": None, + "mirror": None, + "homepage": None, + "depends": [], + "resource": [], + "conflicts": [], + "patches": [], + "install": [] + } + + +def _error(msg, err): + print("ERROR: {} - {}".format(msg, err), file=sys.stderr) + + +def _name(): + t = _clean(next(line)) + if 'class' not in t: + return # Might be text at the top of file. + try: + t = t.split()[1] + except IndexError as err: + if "class" in t: + _error("_name()", err) + raise err + else: + pass + result['name'] = t + + +def _patch(): + url = None + strip = None + data = None + + if x.endswith("__END__"): + data = [] + while True: + try: + data.append(next(line)) + except StopIteration: + break + d = {"url": url, "data": data} + result["patches"].append(d) + return + try: + t = re.match(r'(?:patch) :p?(\d|DATA)', x).groups(0)[0] + except AttributeError: + """ `patch do` would be the case here, assume strip=1 """ + t = "1" + if "DATA" in t: + """ We'll get called later when __END__ appears """ + # print("Expecting DATA at EOF.") # Debug line + return + else: + strip = t + while True: + a = _clean(next(line)) + # print("----> {}".format(a)) # Debug + if a.startswith("url"): + try: + url = regex_quoted.findall(a)[0] + except IndexError as err: + _error("IndexError in _patch()", err) + return -1 + if a.startswith("end"): + break + d = {"url": url, "strip": strip} + result["patches"].append(d) + + +def _resource(): + name = None + url = None + if not regex_resource.match(x): + return # TEMP, CLEAN UP + # Resource "XX" do + try: + name = regex_quoted.findall(x)[0] + except IndexError as err: + _error("IndexError in _resource() (name)", err) + return -1 + while True: + try: + t = _clean(next(line)) + except StopIteration as err: + _error("StopIteration in _resource()", err) + break + # print(t) # debug + if t.startswith("url"): + try: + url = regex_quoted.findall(t)[0] + except IndexError as err: + _error("IndexError in _resource() (url)", err) + return -1 + if t.startswith("end"): + break + d = {"name": name, "url": url} + result["resource"].append(d) + return + + +def _homepage(): + try: + homepage = regex_quoted.findall(x)[0] + result['homepage'] = homepage + return + except IndexError as err: + _error("IndexError in _homepage()", err) + return -1 + + +def _url(): + try: + url = regex_quoted.findall(x)[0] + if not result['url']: + result['url'] = url + return None + else: + return url + except IndexError as err: + _error("IndexError in _url()", err) + return None + + +def _mirror(): + mirror = _url() + if mirror: + result['mirror'] = mirror + else: + return -1 + + +def _bottle(): + return -1 + + +def _description(): + try: + description = regex_quoted.findall(_x)[0] + result['description'] = description + except IndexError as err: + _error("IndexError in _description()", err) + return -1 + return + + +def _clean(_line): + """ Strips new lines and comments""" + _line = _line.strip() + if "# " in _line: + _line = _line[:_line.index('#')] + return _line + + +def _depends(): + name = None + build = False # Build Dependency + try: + a = None + try: + a = re.findall(r'depends_on :(\S*)', x)[0] + except IndexError: + pass + if a: + name = a + else: + name = regex_quoted.findall(x)[0] + except IndexError as err: + _error("IndexError in _depends(): line {}".format(x), err) + return -1 + if x.endswith(":build"): + build = True + d = {'depend': name, 'build-depend': build} + result["depends"].append(d) + return + + +def _conflicts(): + name = None + reason = None + try: + if ':because ' in x: + t = x.split(':because ')[1] + reason = regex_quoted.findall(t)[0] + name = regex_quoted.findall(x)[0] + except IndexError as err: + _error("IndexError in _conflicts()", err) + return -1 + d = {'conflict': name, 'reason': reason} + result['conflicts'].append(d) + return + +def _install(): + grammar = re.compile(r'( do|if )') + l = [] + c = 0 + while True: + a = _clean(next(line)) + if grammar.match(a): + c += 1 + elif a.startswith("end"): + if c <= 0: + break + else: + c -= 1 + l.append(a) + result["install"] = l + return + + +def _def(): + if "install" in x: + _install() + return -1 + + +def _keywords(word): + if word.startswith("desc") and not result['description']: + _description() + elif word.startswith("homepage") and not result['homepage']: + _homepage() + elif word.startswith("url") and not result['url']: + _url() + elif word.startswith("mirror") and not result['mirror']: + _mirror() + elif word.startswith("bottle"): + _bottle() + elif word.startswith("patch") or word.startswith("__END__"): + _patch() + elif word.startswith("resource"): + _resource() + elif word.startswith("depends_on"): + _depends() + elif word.startswith("conflicts_with"): + _conflicts() + elif word.startswith("def"): + _def() + else: + return -1 + + +def _parse(file): + """ Reads the data """ + global line, x, _x + # a = 0 # debug + with open(file) as line: + line = iter(line) + while not result["name"]: + _name() + for x in line: + _x = x # Temp workaround for "#" in descriptions + x = _clean(x) + # a += 1 # debug + # print("{} {}".format(a, x)) # Debug + if keywords.match(x): + # print("keywords match ({}) found! {}".format(keywords.search(x).group(1), x)) # DEBUG + _keywords(keywords.search(x).group(1)) + + +def parse(file): + _reset() + _parse(file) + return result diff --git a/util/.marauder/marauder/version.py b/util/.marauder/marauder/version.py new file mode 100644 index 000000000..6ad09d9fe --- /dev/null +++ b/util/.marauder/marauder/version.py @@ -0,0 +1,40 @@ +import os +from io import BytesIO +import re +from urllib.request import urlopen +import sys + +default = re.compile(r'(?:([0-9]+(?:[.-_][0-9]+)+))') # Version() + +""" Takes URL string and guesses version """ +def version(url): + filename = os.path.basename(url) + version = default.findall(filename) + if not version: + x = os.path.basename(os.path.dirname(url)) + version = default.findall(x) # Go up one directory and try that. + if version: + return version[0] + version = re.findall(r'\S*?(:?[0-9-]+)', filename) # v40 or program-83 for example. + if version: + return version[0] + if url.endswith(".git"): + return None # FIXME: this is too slow. + # print(f"Finding version for {url}", file=sys.stderr) + latest_release = os.popen( + f"git ls-remote --tags {url} 2>/dev/null | sort -Vk2 | awk 'END{{ print $2 }}' | grep -oE '[0-9]+(\\.[0-9]+)+'" + ).read().strip() + latest_commit = os.popen( + f"git ls-remote --tags {url} 2>/dev/null | sort -Vk2 | awk 'END{{ print $1 }}'" + ).read().strip() + if latest_release and latest_commit: + version = f"{latest_release}-git-{latest_commit[:8]}" + elif latest_commit: + version = f"1.0-git-{latest_commit[:8]}" + else: + return None + return version + + if not version: # If still no result. + return None + return version[0] |