add support for python installer

The best I could come up with for allowing compile_seccomp_policy
to be an executable script installed via setup.py.

Originally I cooked up a trick where setup.py also had:

data_files=[('minijail', ['constants.json'])],

and compile_seccomp_policy.py used:

constants_file = 'constants.json'
if pkg_resources.resource_exists(__name__, constants_file):
    constants_file = pkg_resources.resource_filename(__name__, constants_file)

so that a package can ship with a constants.json and auotmatically use
it.  This works when installed as a 'dist-package' egg, but CrOS installs
as a 'site-package' where this trick don't work (constants.json ends up in
another location under /usr, not to mention being stored with a board) and it
complicates the dependency story for the Makefile so I punted.

For both 'dist-package' and 'site-package' the plain "import XXX" form doesn't work
for files located in the same directory (results in a ModuleNotFoundError error),
so I've added a "from minijail import XXX" fallback so new & original cases both
work okay.

Bug: None
Test: `make tests`.  Ran 'python3 setup.py install --record files.txt'
and verified the stubs in /usr/local/bin could be used to launch the 3
scripts without import errors.

Change-Id: I61fe0b624960c89fd715c1c60213edc2b736ad1c
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..ab02ddf
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2020 The Android Open Source Project
+#
+# 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.
+"""A file that specifies how to install minijail's python-based tool(s)."""
+
+import os
+from setuptools import setup
+
+
+this_directory = os.path.abspath(os.path.dirname(__file__))
+with open(os.path.join(this_directory, 'README.md'), encoding='utf-8') as f:
+    long_description = f.read()
+
+setup(name='minijail',
+      version='0.12',
+      description='A set of tools for Minijail',
+      classifiers=[
+          'Programming Language :: Python :: 3',
+          'License :: OSI Approved :: Apache Software License',
+          'Operating System :: Linux',
+      ],
+      python_requires='>=3.6',
+      license='Apache License 2.0',
+      long_description=long_description,
+      long_description_content_type='text/markdown',
+      author='Minijail Developers',
+      author_email='[email protected]',
+      url='https://google.github.io/minijail/',
+      packages=['minijail'],
+      package_dir={'minijail': 'tools'},
+      entry_points={
+          'console_scripts': [
+              'compile_seccomp_policy = minijail.compile_seccomp_policy:main',
+              'generate_seccomp_policy = minijail.generate_seccomp_policy:main',
+              'generate_constants_json = minijail.generate_constants_json:main',
+          ],
+      },
+)
diff --git a/tools/README.md b/tools/README.md
index 95997af..d056797 100644
--- a/tools/README.md
+++ b/tools/README.md
@@ -37,12 +37,6 @@
 The generated BPF code can be analyzed using
 [libseccomp](https://github.com/seccomp/libseccomp)'s `tools/scmp_bpf_disasm`.
 
-*** note
-**Note:** This tool is currently only supported for native and Android builds.
-In Chrome OS builds, the build-time generation of arch-specific `constants.json`
-is not yet enabled.
-***
-
 ### Sample usage
 
 ```shell
diff --git a/tools/compile_seccomp_policy.py b/tools/compile_seccomp_policy.py
index 5887e91..f3b9eea 100755
--- a/tools/compile_seccomp_policy.py
+++ b/tools/compile_seccomp_policy.py
@@ -25,10 +25,16 @@
 import argparse
 import sys
 
-import arch
-import bpf
-import compiler
-import parser
+try:
+    import arch
+    import bpf
+    import compiler
+    import parser
+except ImportError:
+    from minijail import arch
+    from minijail import bpf
+    from minijail import compiler
+    from minijail import parser
 
 
 def parse_args(argv):
@@ -61,8 +67,12 @@
     return parser.parse_args(argv)
 
 
-def main(argv):
+def main(argv=None):
     """Main entrypoint."""
+
+    if argv is None:
+        argv = sys.argv[1:]
+
     opts = parse_args(argv)
     parsed_arch = arch.Arch.load_from_json(opts.arch_json)
     policy_compiler = compiler.PolicyCompiler(parsed_arch)
diff --git a/tools/compiler.py b/tools/compiler.py
index 4e3881a..161eadf 100644
--- a/tools/compiler.py
+++ b/tools/compiler.py
@@ -20,8 +20,12 @@
 
 import enum
 
-import bpf
-import parser  # pylint: disable=wrong-import-order
+try:
+    import bpf
+    import parser  # pylint: disable=wrong-import-order
+except ImportError:
+    from minijail import bpf
+    from minijail import parser  # pylint: disable=wrong-import-order
 
 
 class OptimizationStrategy(enum.Enum):
diff --git a/tools/generate_constants_json.py b/tools/generate_constants_json.py
index ae958ab..814c4ae 100755
--- a/tools/generate_constants_json.py
+++ b/tools/generate_constants_json.py
@@ -72,8 +72,12 @@
     return ParseResults(table_name=table_name, table_entries=table_entries)
 
 
-def main(argv):
+def main(argv=None):
     """Main entrypoint."""
+
+    if argv is None:
+        argv = sys.argv[1:]
+
     parser = argparse.ArgumentParser(description=__doc__)
     parser.add_argument('--output',
                         help='The path of the generated constants.json file.',
diff --git a/tools/generate_seccomp_policy.py b/tools/generate_seccomp_policy.py
index fe122d5..2cfb611 100755
--- a/tools/generate_seccomp_policy.py
+++ b/tools/generate_seccomp_policy.py
@@ -117,8 +117,12 @@
                 arg_inspection[syscall].value_set.add(arg_value)
 
 
-def main(argv):
+def main(argv=None):
     """Main entrypoint."""
+
+    if argv is None:
+        argv = sys.argv[1:]
+
     opts = parse_args(argv)
 
     syscalls = collections.defaultdict(int)
diff --git a/tools/parser.py b/tools/parser.py
index d58dbd6..a2ba336 100644
--- a/tools/parser.py
+++ b/tools/parser.py
@@ -25,7 +25,11 @@
 import os.path
 import re
 
-import bpf
+try:
+    import bpf
+except ImportError:
+    from minijail import bpf
+
 
 Token = collections.namedtuple(
     'Token', ['type', 'value', 'filename', 'line', 'line_number', 'column'])