Skip to content

Commit

Permalink
move cli arg parsing to own file
Browse files Browse the repository at this point in the history
  • Loading branch information
linuxlizard committed Jul 4, 2023
1 parent 1e995ea commit 4bb0eb1
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 139 deletions.
142 changes: 142 additions & 0 deletions pymake/pargs.py
@@ -0,0 +1,142 @@
#!/usr/bin/env python3

import sys
import getopt

from pymake.version import Version

def usage():
# options are designed to be 100% compatible with GNU Make
# please keep this list in alphabetical order (but with identical commands
# still grouped together)
print("""Usage: pymake [options] [target] ...)

Check warning on line 12 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L12

Added line #L12 was not covered by tests
Options:
-B
--always-make
TODO Unconditionally build targets.
-C dir
--directory dir
change to directory before reading makefiles or doing anything else.
-d Print extra debugging information.
-f FILE
--file FILE
--makefile FILE
Read FILE as a makefile.
-h
--help
Print this help message and exit.
-r
--no-builtin-rules
Disable reading GNU Make's built-in rules.
-v
--version
Print the version number and exit.
--warn-undefined-variables
Warn whenever an undefined variable is referenced.
Options not in GNU Make:
--dotfile FILE
Write the Rules' dependency graph as a GraphViz dot file. (Work in progress.)
--html FILE
Write the Rules' dependency graph as an HTML file. (Work in progress.)
--explain Give a verbose error message for common GNU Make errors.
--output FILE
Rewrite the parsed makefile to FILE.
-S Print the makefile as an S-Expression. (Useful for debugging pymake itself.)
""")

class Args:
def __init__(self):
self.debug = 0

Check warning on line 50 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L50

Added line #L50 was not covered by tests

# write rules' dependencies to graphviz .dot file
self.dotfile = None

Check warning on line 53 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L53

Added line #L53 was not covered by tests

# write rules' dependencies to HTML .html file
self.htmlfile = None

Check warning on line 56 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L56

Added line #L56 was not covered by tests

# input filename to parse
self.filename = None

Check warning on line 59 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L59

Added line #L59 was not covered by tests

# rewrite the parsed Makefile to this file
self.output = None

Check warning on line 62 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L62

Added line #L62 was not covered by tests

# print the parsed makefile as an S-Expression
self.s_expr = False

Check warning on line 65 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L65

Added line #L65 was not covered by tests

self.always_make = False

Check warning on line 67 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L67

Added line #L67 was not covered by tests

self.no_builtin_rules = False

Check warning on line 69 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L69

Added line #L69 was not covered by tests

# extra arguments on the command line, interpretted either as a target
# or a GNU Make expression
self.argslist = []

Check warning on line 73 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L73

Added line #L73 was not covered by tests

# -C aka --directory option
self.directory = None

Check warning on line 76 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L76

Added line #L76 was not covered by tests

self.warn_undefined_variables = False
self.detailed_error_explain = False

Check warning on line 79 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L78-L79

Added lines #L78 - L79 were not covered by tests

def parse_args(argv):
print_version ="""PY Make %s. Work in Progress.

Check warning on line 82 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L82

Added line #L82 was not covered by tests
Copyright (C) 2014-2023 David Poole davep@mbuf.com, testcluster@gmail.com""" % (Version.vstring(),)

args = Args()
optlist, arglist = getopt.gnu_getopt(argv, "Bhvo:drSf:C:",

Check warning on line 86 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L85-L86

Added lines #L85 - L86 were not covered by tests
[
"help",
"always-make",
"debug",
"dotfile=",
"html=",
"explain",
"file=",
"makefile=",
"output=",
"no-builtin-rules",
"version",
"warn-undefined-variables",
"directory=",
]
)
for opt in optlist:
if opt[0] in ("-B", "--always-make"):
args.always_make = True

Check warning on line 105 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L105

Added line #L105 was not covered by tests
elif opt[0] in ("-f", "--file", "--makefile"):
args.filename = opt[1]

Check warning on line 107 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L107

Added line #L107 was not covered by tests
elif opt[0] in ('-o', "--output"):
args.output = opt[1]

Check warning on line 109 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L109

Added line #L109 was not covered by tests
elif opt[0] == '-S':
args.s_expr = True

Check warning on line 111 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L111

Added line #L111 was not covered by tests
elif opt[0] == '-d':
args.debug += 1

Check warning on line 113 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L113

Added line #L113 was not covered by tests
elif opt[0] in ("-h", "--help"):
usage()
sys.exit(0)

Check warning on line 116 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L115-L116

Added lines #L115 - L116 were not covered by tests
elif opt[0] in ("-r", "--no-builtin-rules"):
args.no_builtin_rules = True

Check warning on line 118 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L118

Added line #L118 was not covered by tests
elif opt[0] in ("-v", "--version"):
print(print_version)
sys.exit(0)

Check warning on line 121 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L120-L121

Added lines #L120 - L121 were not covered by tests
elif opt[0] == "--warn-undefined-variables":
args.warn_undefined_variables = True

Check warning on line 123 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L123

Added line #L123 was not covered by tests
elif opt[0] == "--explain":
args.detailed_error_explain = True

Check warning on line 125 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L125

Added line #L125 was not covered by tests
elif opt[0] == "--dotfile":
args.dotfile = opt[1]

Check warning on line 127 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L127

Added line #L127 was not covered by tests
elif opt[0] == "--html":
args.htmlfile = opt[1]

Check warning on line 129 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L129

Added line #L129 was not covered by tests
elif opt[0] in ("-C", "--directory"):
# multiple -C options are supported for reasons I don't understand
if args.directory is None:
args.directory = []
args.directory.append(opt[1])

Check warning on line 134 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L133-L134

Added lines #L133 - L134 were not covered by tests
else:
# wtf?
assert 0, opt

Check warning on line 137 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L137

Added line #L137 was not covered by tests

args.argslist = arglist
return args

Check warning on line 140 in pymake/pargs.py

View check run for this annotation

Codecov / codecov/patch

pymake/pargs.py#L139-L140

Added lines #L139 - L140 were not covered by tests


143 changes: 4 additions & 139 deletions pymake/pymake.py
Expand Up @@ -11,13 +11,11 @@
import logging
import os
import os.path
import getopt

logger = logging.getLogger("pymake")
#logging.basicConfig(level=logging.DEBUG)

from pymake.scanner import ScannerIterator
from pymake.version import Version
import pymake.vline as vline
import pymake.symbolmk as symbolmk
from pymake.symbolmk import *
Expand All @@ -30,6 +28,7 @@
import pymake.makedb as makedb
import pymake.rules as rules
import pymake.shell as shell
import pymake.pargs as pargs

def get_basename( filename ) :
return os.path.splitext( os.path.split( filename )[1] )[0]
Expand Down Expand Up @@ -389,7 +388,7 @@ def check_prefixes(s):
# makefile in our same process context.
if ret.is_submake:
submake_argv = ret.stdout.strip().split("\n")
args = parse_args(submake_argv[1:])
args = pargs.parse_args(submake_argv[1:])

Check warning on line 391 in pymake/pymake.py

View check run for this annotation

Codecov / codecov/patch

pymake/pymake.py#L391

Added line #L391 was not covered by tests
# breakpoint()
currwd = os.getcwd()
exit_code = _run_it(args)
Expand All @@ -411,7 +410,7 @@ def check_prefixes(s):

def execute(makefile, args):
# ha ha type checking
assert isinstance(args, Args)
assert isinstance(args, pargs.Args)

Check warning on line 413 in pymake/pymake.py

View check run for this annotation

Codecov / codecov/patch

pymake/pymake.py#L413

Added line #L413 was not covered by tests

# tinkering with how to evaluate
logger.info("Starting execute of %s", id(makefile))
Expand Down Expand Up @@ -538,146 +537,12 @@ def _run_it(args):
exit_code = execute(makefile, args)
return exit_code

def usage():
# options are designed to be 100% compatible with GNU Make
# please keep this list in alphabetical order (but with identical commands
# still grouped together)
print("""Usage: pymake [options] [target] ...)
Options:
-B
--always-make
TODO Unconditionally build targets.
-C dir
--directory dir
change to directory before reading makefiles or doing anything else.
-d Print extra debugging information.
-f FILE
--file FILE
--makefile FILE
Read FILE as a makefile.
-h
--help
Print this help message and exit.
-r
--no-builtin-rules
Disable reading GNU Make's built-in rules.
-v
--version
Print the version number and exit.
--warn-undefined-variables
Warn whenever an undefined variable is referenced.
Options not in GNU Make:
--dotfile FILE
Write the Rules' dependency graph as a GraphViz dot file. (Work in progress.)
--html FILE
Write the Rules' dependency graph as an HTML file. (Work in progress.)
--explain Give a verbose error message for common GNU Make errors.
--output FILE
Rewrite the parsed makefile to FILE.
-S Print the makefile as an S-Expression. (Useful for debugging pymake itself.)
""")

class Args:
def __init__(self):
self.debug = 0

# write rules' dependencies to graphviz .dot file
self.dotfile = None

# write rules' dependencies to HTML .html file
self.htmlfile = None

# input filename to parse
self.filename = None

# rewrite the parsed Makefile to this file
self.output = None

# print the parsed makefile as an S-Expression
self.s_expr = False

self.always_make = False

self.no_builtin_rules = False

# extra arguments on the command line, interpretted either as a target
# or a GNU Make expression
self.argslist = []

# -C aka --directory option
self.directory = None

self.warn_undefined_variables = False
self.detailed_error_explain = False

def parse_args(argv):
print_version ="""PY Make %s. Work in Progress.
Copyright (C) 2014-2023 David Poole davep@mbuf.com, testcluster@gmail.com""" % (Version.vstring(),)

args = Args()
optlist, arglist = getopt.gnu_getopt(argv, "Bhvo:drSf:C:",
[
"help",
"always-make",
"debug",
"dotfile=",
"html=",
"explain",
"file=",
"makefile=",
"output=",
"no-builtin-rules",
"version",
"warn-undefined-variables",
"directory=",
]
)
for opt in optlist:
if opt[0] in ("-B", "--always-make"):
args.always_make = True
elif opt[0] in ("-f", "--file", "--makefile"):
args.filename = opt[1]
elif opt[0] in ('-o', "--output"):
args.output = opt[1]
elif opt[0] == '-S':
args.s_expr = True
elif opt[0] == '-d':
args.debug += 1
elif opt[0] in ("-h", "--help"):
usage()
sys.exit(0)
elif opt[0] in ("-r", "--no-builtin-rules"):
args.no_builtin_rules = True
elif opt[0] in ("-v", "--version"):
print(print_version)
sys.exit(0)
elif opt[0] == "--warn-undefined-variables":
args.warn_undefined_variables = True
elif opt[0] == "--explain":
args.detailed_error_explain = True
elif opt[0] == "--dotfile":
args.dotfile = opt[1]
elif opt[0] == "--html":
args.htmlfile = opt[1]
elif opt[0] in ("-C", "--directory"):
# multiple -C options are supported for reasons I don't understand
if args.directory is None:
args.directory = []
args.directory.append(opt[1])
else:
# wtf?
assert 0, opt

args.argslist = arglist
return args

# FIXME ugly hack dependency injection to solve problems with circular imports
parsermk.parse_vline_stream = parse_vline_stream
symbolmk.tokenize_statement = tokenize_statement

def main():
args = parse_args(sys.argv[1:])
args = pargs.parse_args(sys.argv[1:])

Check warning on line 545 in pymake/pymake.py

View check run for this annotation

Codecov / codecov/patch

pymake/pymake.py#L545

Added line #L545 was not covered by tests

if args.debug:
logging.basicConfig(level=logging.DEBUG)
Expand Down

0 comments on commit 4bb0eb1

Please sign in to comment.