# Path: python/gup/whichcraft.py
# def which(cmd, mode=os.F_OK | os.X_OK, path=None):
#     """Given a command, mode, and a PATH string, return the path which
#     conforms to the given mode on the PATH, or None if there is no such
#     file.
#     `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
#     of os.environ.get("PATH"), or can be overridden with a custom search
#     path.
#     Note: This function was backported from the Python 3 source code.
#     """
#     # Check that a given file can be accessed with the correct mode.
#     # Additionally check that `file` is not a directory, as on Windows
#     # directories pass the os.access check.
#     def _access_check(fn, mode):
#         return (os.path.exists(fn) and os.access(fn, mode) and
#                 not os.path.isdir(fn))
# 
#     # If we're given a path with a directory part, look it up directly
#     # rather than referring to PATH directories. This includes checking
#     # relative to the current directory, e.g. ./script
#     if os.path.dirname(cmd):
#         if _access_check(cmd, mode):
#             return cmd
#         return None
# 
#     if path is None:
#         path = os.environ.get("PATH", os.defpath)
#     if not path:
#         return None
#     path = path.split(os.pathsep)
# 
#     if sys.platform == "win32":
#         # The current directory takes precedence on Windows.
#         if os.curdir not in path:
#             path.insert(0, os.curdir)
# 
#         # PATHEXT is necessary to check on Windows.
#         pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
#         # See if the given file matches any of the expected path
#         # extensions. This will allow us to short circuit when given
#         # "python.exe". If it does match, only test that one, otherwise we
#         # have to try others.
#         if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
#             files = [cmd]
#         else:
#             files = [cmd + ext for ext in pathext]
#     else:
#         # On other platforms you don't have things like PATHEXT to tell you
#         # what file suffixes are executable, so just pass on cmd as-is.
#         files = [cmd]
# 
#     seen = set()
#     for dir in path:
#         normdir = os.path.normcase(dir)
#         if normdir not in seen:
#             seen.add(normdir)
#             for thefile in files:
#                 name = os.path.join(dir, thefile)
#                 if _access_check(name, mode):
#                     return name
#     return None
# 
# Path: python/gup/log.py
# def getLogger(*a):
# 	logger = logging.getLogger(*a)
# 	logger.addFilter(_color_filter)
# 	return logger
# 
# Path: python/gup/error.py
# class SafeError(Exception):
# 	exitcode = 10
# 	pass
# 
# Path: python/gup/var.py
# INDENT = os.environ.get('GUP_INDENT', '')
# 
# PY3 = sys.version_info >= (3,0)


import os
import re
import itertools
	import doctest
from os import path
from .whichcraft import which
from .log import getLogger
from .error import SafeError
from .var import INDENT, PY3
		if not self.indirect:
			if target_is_builder():
				_log.debug("ignoring direct builder for target %s", path)
				# gupfiles & scripts can only be built by Gupfile targets, not .gup scripts
				return None
			return Builder(path, self.target, build_basedir, parent=None)

		with open(path) as f:
			try:
				rules = parse_gupfile(f)
			except AssertionError as e:
				reason = " (%s)" % (e.message,) if e.message else ""
				raise SafeError("Invalid %s: %s%s" % (GUPFILE, path, reason))
			_log.trace("Parsed gupfile: %r" % rules)
	
		match_target = self.target
		# always use `/` as path sep in gupfile patterns
		if os.path.sep != '/':
			match_target = self.target.replace(os.path.sep, '/')

		def find_matching_rule(matchfn, target, match_target):
			for script, ruleset in rules:
				if matchfn(ruleset, match_target):
					base = os.path.realpath(build_basedir)
					parent = None

					if script.startswith('!'):
						script = script[1:]
						script_path = which(script)
						if script_path is None:

# Path: python/gup/whichcraft.py
# def which(cmd, mode=os.F_OK | os.X_OK, path=None):
#     """Given a command, mode, and a PATH string, return the path which
#     conforms to the given mode on the PATH, or None if there is no such
#     file.
#     `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
#     of os.environ.get("PATH"), or can be overridden with a custom search
#     path.
#     Note: This function was backported from the Python 3 source code.
#     """
#     # Check that a given file can be accessed with the correct mode.
#     # Additionally check that `file` is not a directory, as on Windows
#     # directories pass the os.access check.
#     def _access_check(fn, mode):
#         return (os.path.exists(fn) and os.access(fn, mode) and
#                 not os.path.isdir(fn))
# 
#     # If we're given a path with a directory part, look it up directly
#     # rather than referring to PATH directories. This includes checking
#     # relative to the current directory, e.g. ./script
#     if os.path.dirname(cmd):
#         if _access_check(cmd, mode):
#             return cmd
#         return None
# 
#     if path is None:
#         path = os.environ.get("PATH", os.defpath)
#     if not path:
#         return None
#     path = path.split(os.pathsep)
# 
#     if sys.platform == "win32":
#         # The current directory takes precedence on Windows.
#         if os.curdir not in path:
#             path.insert(0, os.curdir)
# 
#         # PATHEXT is necessary to check on Windows.
#         pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
#         # See if the given file matches any of the expected path
#         # extensions. This will allow us to short circuit when given
#         # "python.exe". If it does match, only test that one, otherwise we
#         # have to try others.
#         if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
#             files = [cmd]
#         else:
#             files = [cmd + ext for ext in pathext]
#     else:
#         # On other platforms you don't have things like PATHEXT to tell you
#         # what file suffixes are executable, so just pass on cmd as-is.
#         files = [cmd]
# 
#     seen = set()
#     for dir in path:
#         normdir = os.path.normcase(dir)
#         if normdir not in seen:
#             seen.add(normdir)
#             for thefile in files:
#                 name = os.path.join(dir, thefile)
#                 if _access_check(name, mode):
#                     return name
#     return None
# 
# Path: python/gup/log.py
# def getLogger(*a):
# 	logger = logging.getLogger(*a)
# 	logger.addFilter(_color_filter)
# 	return logger
# 
# Path: python/gup/error.py
# class SafeError(Exception):
# 	exitcode = 10
# 	pass
# 
# Path: python/gup/var.py
# INDENT = os.environ.get('GUP_INDENT', '')
# 
# PY3 = sys.version_info >= (3,0)


# Path: python/gup/gupfile.py
import os
import re
import itertools
	import doctest
from os import path
from .whichcraft import which
from .log import getLogger
from .error import SafeError
from .var import INDENT, PY3

		if not self.indirect:
			if target_is_builder():
				_log.debug("ignoring direct builder for target %s", path)
				# gupfiles & scripts can only be built by Gupfile targets, not .gup scripts
				return None
			return Builder(path, self.target, build_basedir, parent=None)

		with open(path) as f:
			try:
				rules = parse_gupfile(f)
			except AssertionError as e:
				reason = " (%s)" % (e.message,) if e.message else ""
				raise SafeError("Invalid %s: %s%s" % (GUPFILE, path, reason))
			_log.trace("Parsed gupfile: %r" % rules)
	
		match_target = self.target
		# always use `/` as path sep in gupfile patterns
		if os.path.sep != '/':
			match_target = self.target.replace(os.path.sep, '/')

		def find_matching_rule(matchfn, target, match_target):
			for script, ruleset in rules:
				if matchfn(ruleset, match_target):
					base = os.path.realpath(build_basedir)
					parent = None

					if script.startswith('!'):
						script = script[1:]
						script_path = which(script)
						if script_path is None:

							raise SafeError("Build command not found on PATH: %s\n     %s(specified in %s)" % (script, INDENT, path))