1"""This module defines custom ``generate_source_manifest`` setuptools
2command."""
3
4import os
5import subprocess
6import sys
7
8from distutils.cmd import Command
9
10from . import set_build_base_mixin
11from ..constants import SKBUILD_DIR, SKBUILD_MARKER_FILE
12from ..utils import new_style
13
14
15class generate_source_manifest(set_build_base_mixin, new_style(Command)):
16    """Custom setuptools command generating a `MANIFEST` file if
17    not already provided."""
18
19    description = "generate source MANIFEST"
20
21    # pylint:disable=no-self-use
22    def initialize_options(self):
23        """Set default values for all the options that this command supports."""
24        pass
25
26    def run(self):
27        """
28        If neither a `MANIFEST`, nor a `MANIFEST.in` file is provided, and
29        we are in a git repo, try to create a `MANIFEST` file from the output of
30        `git ls-tree --name-only -r HEAD`.
31
32        We need a reliable way to tell if an existing `MANIFEST` file is one
33        we've generated.  distutils already uses a first-line comment to tell
34        if the `MANIFEST` file was generated from `MANIFEST.in`, so we use a
35        dummy file, `_skbuild_MANIFEST`, to avoid confusing distutils.
36        """
37        do_generate = (
38            # If there's a MANIFEST.in file, we assume that we had nothing to do
39            # with the project's manifest.
40            not os.path.exists('MANIFEST.in')
41
42            # otherwise, we check to see that there is no MANIFEST, ...
43            and not os.path.exists('MANIFEST')  # ... or ...
44
45            # ... (if there is one,) that we created it
46            or os.path.exists(SKBUILD_MARKER_FILE())
47        )
48
49        if do_generate:
50
51            try:
52                with open('MANIFEST', 'wb') as manifest_file:
53                    # Since Git < 2.11 does not support --recurse-submodules option, fallback to
54                    # regular listing.
55                    try:
56                        manifest_file.write(
57                            subprocess.check_output(['git', 'ls-files', '--recurse-submodules'])
58                        )
59                    except subprocess.CalledProcessError:
60                        manifest_file.write(
61                             subprocess.check_output(['git', 'ls-files'])
62                         )
63            except subprocess.CalledProcessError:
64                sys.stderr.write(
65                    '\n\n'
66                    'Since scikit-build could not find MANIFEST.in or '
67                    'MANIFEST, it tried to generate a MANIFEST file '
68                    'automatically, but could not because it could not '
69                    'determine which source files to include.\n\n'
70                    'The command used was "git ls-files"\n'
71                    '\n\n'
72                )
73                raise
74
75            if not os.path.exists(SKBUILD_DIR()):
76                os.makedirs(SKBUILD_DIR())
77
78            with open(SKBUILD_MARKER_FILE(), 'w'):  # touch
79                pass
80
81    def finalize_options(self, *args, **kwargs):
82        """Set final values for all the options that this command supports."""
83        pass
84