#!/usr/bin/env python import argparse import os import glob import distutils.cmd import distutils.log from typing import IO, Iterator CURRENT_DIR = os.path.abspath(os.path.dirname(__file__)) BOTS_DIR = os.path.normpath(os.path.join(CURRENT_DIR, 'zulip_bots', 'bots')) MANIFEST_PATH = os.path.join(CURRENT_DIR, 'MANIFEST.in') class GenerateManifest(distutils.cmd.Command): """ A custom setup.py command to generate a MANIFEST.in for the zulip_bots package. """ description = 'generate a MANIFEST.in for PyPA or for development' user_options = [ ('release', None, 'generate a MANIFEST for a PyPA release'), ] def initialize_options(self): # type: () -> None self.release = False def finalize_options(self): # type: () -> None pass def run(self): # type: () -> None if self.release: generate_release_manifest() self.announce( # type: ignore # error: "GenerateManifest" has no attribute "announce" 'Generating a MANIFEST for a PyPA release of zulip_bots.', level=distutils.log.INFO # type: ignore # error: Module has no attribute "INFO" ) else: generate_dev_manifest() self.announce( # type: ignore 'Generating a MANIFEST for zulip_bots\' development.', level=distutils.log.INFO # type: ignore ) def get_test_fixtures(): # type: () -> Iterator[str] glob_pattern = os.path.join(BOTS_DIR, '*', 'fixtures', '*.json') fixtures_paths = map( lambda fp: os.path.join(*fp.split(os.path.sep)[-5:]).replace(os.path.sep, '/'), glob.glob(glob_pattern) ) return fixtures_paths def get_logos(): # type: () -> Iterator[str] glob_pattern = os.path.join(BOTS_DIR, '*', 'logo.*') logo_paths = map( lambda fp: os.path.join(*fp.split(os.path.sep)[-4:]).replace(os.path.sep, '/'), glob.glob(glob_pattern) ) return logo_paths def get_docs(): # type: () -> Iterator[str] glob_pattern = os.path.join(BOTS_DIR, '*', 'doc.md') doc_paths = map( lambda fp: os.path.join(*fp.split(os.path.sep)[-4:]).replace(os.path.sep, '/'), glob.glob(glob_pattern) ) return doc_paths def get_assets(): # type: () -> Iterator[str] glob_pattern = os.path.join(BOTS_DIR, '*', 'assets', '*') assets_files = map( lambda fp: os.path.join(*fp.split(os.path.sep)[-5:]).replace(os.path.sep, '/'), glob.glob(glob_pattern) ) return assets_files def generate_and_write(filepaths, file_obj): # type: (Iterator[str], IO[str]) -> None template = 'include {line}\n' lines = map(lambda line: template.format(line=line), filepaths) file_obj.writelines(lines) file_obj.write('\n') def generate_dev_manifest(): # type: () -> None with open(MANIFEST_PATH, 'w') as fp: generate_and_write(get_test_fixtures(), fp) generate_and_write(get_logos(), fp) generate_and_write(get_docs(), fp) generate_and_write(get_assets(), fp) def generate_release_manifest(): # type: () -> None with open(MANIFEST_PATH, 'w') as fp: generate_and_write(get_docs(), fp) generate_and_write(get_assets(), fp) def parse_args(): # type: () -> argparse.Namespace usage = """ To generate a MANIFEST.in for a PyPA release, run: ./generate_manifest.py --release To generate a MANIFEST.in for development, run without arguments: ./generate_manifest.py """ parser = argparse.ArgumentParser(usage=usage) parser.add_argument('--release', '-r', action='store_true', default=False, help='Generate MANIFEST.in for a PyPA release.') return parser.parse_args() def main(): # type: () -> None options = parse_args() if options.release: generate_release_manifest() else: generate_dev_manifest() if __name__ == '__main__': main()