blob: e6f466d50384f1c740dd9b1577ed53c71c15d25e [file] [log] [blame]
# Copyright 2020 The Cobalt Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Gyp extensions, called with pymod_do_main."""
import argparse
import glob
import logging
import os
import stat
import sys
# lifted from standard lib webbrowser.py
def isexecutable(cmd):
"""Returns whether the input file is an exectuable."""
if sys.platform[:3] == 'win':
extensions = ('.exe', '.bat', '.cmd')
cmd = cmd.lower()
if cmd.endswith(extensions) and os.path.isfile(cmd):
return cmd
for ext in extensions:
if os.path.isfile(cmd + ext):
return cmd + ext
else:
if os.path.isfile(cmd):
mode = os.stat(cmd)[stat.ST_MODE]
if mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH):
return cmd
class ExtensionCommandParser(argparse.ArgumentParser):
"""Helper class for parsing arguments to extended gyp functions."""
def __init__(self, list_args):
argparse.ArgumentParser.__init__(self)
for arg in list_args:
self.add_argument(arg)
def error(self, message):
print('Parse error in gyp_functions.py:' + message)
raise NotImplementedError('Parse error:' + message)
class Extensions(object):
"""Container class for extended functionality for gyp.
Supports operations such as:
- file globbing
- checking file or directory existence
- string manipulations
- retrieving environment variables
- searching PATH and PYTHONPATH for programs.
"""
def __init__(self, argv):
parser = argparse.ArgumentParser()
all_cmds = [x for x in dir(self) if not x.startswith('_')]
parser.add_argument('command', help='Command to run', choices=all_cmds)
args = parser.parse_args(argv[0:1])
self.argv = argv[1:]
self.command = args.command
def call(self):
return getattr(self, self.command)()
def file_glob(self):
"""Glob files in dir, with pattern glob."""
args = ExtensionCommandParser(['dir', 'pattern']).parse_args(self.argv)
path = os.path.normpath(os.path.join(args.dir, args.pattern))
ret = ''
for f in glob.iglob(path):
ret += f.replace(os.sep, '/') + ' '
return ret.strip()
def basename(self):
"""Basename of list of files"""
parser = ExtensionCommandParser([])
parser.add_argument('input_list', nargs='*')
args = parser.parse_args(self.argv)
ret = [os.path.basename(x) for x in args.input_list]
return ' '.join(ret)
def replace_in_list(self):
"""String replace in a list of arguments"""
parser = ExtensionCommandParser(['old', 'new'])
parser.add_argument('input_list', nargs='*')
args = parser.parse_args(self.argv)
inp = args.input_list
return ' '.join([x.replace(args.old, args.new) for x in inp])
def file_glob_sub(self):
"""Glob files, but return filenames with string replace from->to applied."""
args = ExtensionCommandParser(
['dir', 'pattern', 'from_string', 'to_string']).parse_args(self.argv)
path = os.path.normpath(os.path.join(args.dir, args.pattern))
ret = ''
for f in glob.iglob(path):
ret += f.replace(os.sep, '/').replace(args.from_string,
args.to_string) + ' '
return ret.strip()
def file_exists(self):
"""Checks if a file exists, returning a string '1' if so, or '0'."""
args = ExtensionCommandParser(['file']).parse_args(self.argv)
filepath = args.file.replace(os.sep, '/')
ret = os.path.isfile(filepath)
return str(int(ret))
def dir_exists(self):
"""Checks if a directory exists, returning a string 'True' or 'False'."""
args = ExtensionCommandParser(['dir']).parse_args(self.argv)
return str(os.path.isdir(args.dir))
def str_upper(self):
"""Converts an input string to upper case."""
if self.argv:
args = ExtensionCommandParser(['str']).parse_args(self.argv)
return args.str.upper()
return ''
def find_program(self):
"""Searches for the input program name (.exe, .cmd or .bat)."""
args = ExtensionCommandParser(['program']).parse_args(self.argv)
paths_to_check = []
# Collect all paths in PYTHONPATH.
for i in sys.path:
paths_to_check.append(i.replace(os.sep, '/'))
# Then collect all paths in PATH.
for i in os.environ['PATH'].split(os.pathsep):
paths_to_check.append(i.replace(os.sep, '/'))
# Check all the collected paths for the program.
for path in paths_to_check:
exe = os.path.join(path, args.program)
prog = isexecutable(exe)
if prog:
return prog.replace(os.sep, '/')
# If not in PYTHONPATH and PATH, check upwards until root.
# Note: This is a rare case.
root_dir = os.path.dirname(os.path.abspath(__file__))
previous_dir = os.path.abspath(__file__)
while root_dir and root_dir != previous_dir:
exe = os.path.join(root_dir, args.program)
prog = isexecutable(exe)
if prog:
return prog.replace(os.sep, '/')
previous_dir = root_dir
root_dir = os.path.dirname(root_dir)
logging.error('Failed to find program "{}".'.format(args.program))
return None
def getenv(self):
"""Gets the stored value of an environment variable."""
args = ExtensionCommandParser(['var']).parse_args(self.argv)
value = os.getenv(args.var)
if value is not None:
return value.strip()
return ''
def DoMain(argv): # pylint: disable=invalid-name
"""Script main function."""
return Extensions(argv).call()
if __name__ == '__main__':
print(DoMain(sys.argv[1:]))
sys.exit(0)