cengal.build_tools.build_extensions.versions.v_0.go_extension

  1#!/usr/bin/env python
  2# coding=utf-8
  3
  4# Copyright © 2012-2024 ButenkoMS. All rights reserved. Contacts: <gtalk@butenkoms.space>
  5# 
  6# Licensed under the Apache License, Version 2.0 (the "License");
  7# you may not use this file except in compliance with the License.
  8# You may obtain a copy of the License at
  9# 
 10#     http://www.apache.org/licenses/LICENSE-2.0
 11# 
 12# Unless required by applicable law or agreed to in writing, software
 13# distributed under the License is distributed on an "AS IS" BASIS,
 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15# See the License for the specific language governing permissions and
 16# limitations under the License.
 17
 18
 19__all__ = [
 20    'CengalGoBuildExtension',
 21]
 22
 23
 24"""
 25Module Docstring
 26Docstrings: http://www.python.org/dev/peps/pep-0257/
 27"""
 28
 29__author__ = "ButenkoMS <gtalk@butenkoms.space>"
 30__copyright__ = "Copyright © 2012-2024 ButenkoMS. All rights reserved. Contacts: <gtalk@butenkoms.space>"
 31__credits__ = ["ButenkoMS <gtalk@butenkoms.space>", ]
 32__license__ = "Apache License, Version 2.0"
 33__version__ = "4.4.1"
 34__maintainer__ = "ButenkoMS <gtalk@butenkoms.space>"
 35__email__ = "gtalk@butenkoms.space"
 36# __status__ = "Prototype"
 37__status__ = "Development"
 38# __status__ = "Production"
 39
 40
 41# from distutils.dist import Distribution
 42from os import environ
 43
 44from setuptools._distutils.dist import Distribution
 45
 46from cengal.file_system.path_manager import path_relative_to_src, RelativePath, get_relative_path_part, sep
 47from cengal.file_system.directory_manager import current_src_dir, change_current_dir, ensure_dir
 48from cengal.file_system.directory_manager import filtered_file_list, FilteringType, filtered_file_list_traversal, file_list_traversal, file_list_traversal_ex, FilteringEntity
 49from cengal.file_system.file_manager import current_src_file_dir, file_exists, full_ext, file_name as get_file_name, last_ext
 50from cengal.build_tools.prepare_cflags import prepare_cflags, concat_cflags, prepare_compile_time_env, adjust_definition_names, \
 51    dict_of_tuples_to_dict, list_to_dict
 52from cengal.introspection.inspect import get_exception, exception_to_printable_text, entity_repr_limited_try_qualname, pifrl, pdi
 53from cengal.text_processing.text_processing import find_text
 54from cengal.system import OS_TYPE, TEMPLATE_MODULE_NAME
 55from shutil import rmtree
 56from os import remove
 57from os.path import splitext, normpath, join as path_join, basename, split
 58from setuptools import Extension as SetuptoolsExtension
 59from Cython.Distutils import Extension as CythonExtension
 60from distutils.command.build import build as build_orig
 61from distutils.command.build_ext import build_ext as build_ext_orig
 62from setuptools.command.sdist import sdist as sdist_orig
 63import json
 64import importlib
 65
 66from os.path import isdir, exists, isfile, dirname
 67
 68import setuptools
 69import platform
 70import sys
 71import os
 72
 73from cengal.file_system.path_manager import RelativePath, get_relative_path_part
 74from cengal.file_system.directory_manager import current_src_dir
 75from cengal.file_system.directory_manager import file_list_traversal, FilteringEntity
 76from cengal.build_tools.prepare_cflags import prepare_compile_time_flags, prepare_compile_time_env
 77from cengal.os.execute import prepare_params, escape_text, escape_param, prepare_command
 78from setuptools.discovery import find_package_path
 79import subprocess
 80from pprint import pprint
 81from typing import List, Dict, Optional, Iterable, Callable, Sequence, Tuple, Union, Type, Any
 82
 83from .build_extensions import CengalBuildExtension
 84
 85
 86def wrap_definition_text(text: str) -> str:
 87    return text
 88
 89
 90def wrap_definition_text_v(text: str) -> str:
 91    return escape_param(text)
 92
 93
 94def wrap_definition_text_f(text: str) -> str:
 95    return f'`{text}`'
 96
 97
 98def prepare_definition_value(value: Union[None, bool, int, str]) -> Union[None, str]:
 99    if value is None:
100        return None
101    elif isinstance(value, bool):
102        return 'true' if value else 'false'
103    elif isinstance(value, int):
104        return str(value)
105    elif isinstance(value, str):
106        return wrap_definition_text(value)
107    else:
108        return wrap_definition_text(f'{value}')
109
110
111def prepare_definition_value_v(value: Union[None, bool, int, str]) -> Union[None, str]:
112    if value is None:
113        return None
114    elif isinstance(value, bool):
115        return 'true' if value else 'false'
116    elif isinstance(value, int):
117        return str(value)
118    elif isinstance(value, str):
119        return wrap_definition_text_v(value)
120    else:
121        return wrap_definition_text_v(f'{value}')
122
123
124def prepare_definition_value_f(value: Union[None, bool, int, str]) -> Union[None, str]:
125    if value is None:
126        return None
127    elif isinstance(value, bool):
128        return 'true' if value else 'false'
129    elif isinstance(value, (int, float)):
130        return str(value)
131    elif isinstance(value, str):
132        return wrap_definition_text_f(value)
133    else:
134        return wrap_definition_text_f(f'{value}')
135
136
137def wrap_definition_pair(name: str, value: Any) -> str:
138    return f'-d:{name}' if value is None else f'-d:{name}={value}'
139
140
141def prepare_definition(name: str, value: Optional[Union[bool, int, str]] = None) -> str:
142    return wrap_definition_pair(name, prepare_definition_value(value))
143
144
145def prepare_definition_v(name: str, value: Optional[Union[bool, int, str]] = None) -> str:
146    return wrap_definition_pair(name, prepare_definition_value_v(value))
147
148
149class CengalGoBuildExtension(CengalBuildExtension):
150    base_class: Optional[Type] = None
151    store_as_data: bool = True
152
153    def __init__(self, 
154                 module_name: Optional[str] = None, 
155                 src_dir: str = './src',
156                 out_dir_name: str = 'compiled',
157                 flags: Optional[List[str]] = None, 
158                 definitions: Optional[Union[Sequence[str], Dict[str, Union[Union[None, bool, int, str], Tuple[bool, Union[None, bool, str, int]]]]]] = None, 
159                 additional_build_params: Optional[List[str]] = None, 
160                 additional_go_packages: Optional[List[str]] = None, 
161                 definitions_module_name: str = 'compile_time_py_definitions', 
162                 **kwargs) -> None:
163        super().__init__(kwargs)
164        self.module_name: str = module_name
165        self.out_dir_name: str = out_dir_name
166        self._src_dir: str = src_dir
167        self.src_dir: str = None
168        self.out_dir: str = None
169        self.flags: Optional[List[str]] = flags or list()
170        self.definitions: Optional[Union[Sequence[str], Dict[str, Union[Union[None, bool, int, str], Tuple[bool, Union[None, bool, str, int]]]]]] = definitions or dict()
171        result_flags = adjust_definition_names(list_to_dict(prepare_compile_time_flags()), 'GOF_', 'GOD_')  # GOF is Go Flag; GOD is Go Definition
172        self.result_definitions: Optional[Dict[str, Union[None, bool, int, float, str]]] = adjust_definition_names(prepare_compile_time_env(), 'GOF_', 'GOD_')  # GOF is Go Flag; GOD is Go Definition
173        self.result_definitions.update(result_flags)
174        self.result_definitions.update(dict_of_tuples_to_dict(list_to_dict(definitions)))
175        self.result_definitions.update(list_to_dict(flags))
176        self.additional_build_params: Optional[List[str]] = additional_build_params
177        self.additional_go_packages: Optional[List[str]] = additional_go_packages
178        self.definitions_module_name: str = definitions_module_name
179        self.definitions_module_file_name: str = f'{definitions_module_name}.go'
180    
181    @property
182    def module_name_str(self):
183        if self.module_name:
184            return self.module_name
185        else:
186            namespace = self.name
187            namespace_parts = namespace.split('.')
188            return'/'.join(namespace_parts[:-1])
189    
190    def __call__(self):
191        try:
192            # self.src_dir: str = self._src_dir if os.path.isabs(self._src_dir) else RelativePath(self.dir_path)(self._src_dir)
193            self.src_dir: str = self._src_dir
194            self.out_dir: str = RelativePath(self.dir_path)(self.out_dir_name)
195            print()
196            print('==================================================')
197            print(f'<<< GO COMPILATION: {self.module_name_str} >>>')
198            print('=======================')
199            go_module_setup_files = [
200                'go.mod', 
201                'go.sum', 
202            ]
203            adjusted_exported_files_list = list()
204            need_to_init_go_module = False
205            for file_name in go_module_setup_files:
206                if not file_exists(path_join(self.dir_path, file_name)):
207                    need_to_init_go_module = True
208                    break
209            
210            if need_to_init_go_module:
211                with change_current_dir(self.dir_path):
212                    params = ['go', 'mod', 'init', self.module_name_str]
213                    result = subprocess.run(params, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
214                    print(result.stdout)
215
216            env = os.environ.copy()
217            additional_env = dict()
218            additional_env['LD_LIBRARY_PATH'] = f"{env.get('LD_LIBRARY_PATH', '')}{os.pathsep}."
219            env.update(additional_env)
220            params = ['gopy', 'build', f'-output={self.out_dir_name}', f'-vm={sys.executable}']
221            if self.additional_build_params:
222                params.extend(self.additional_build_params)
223            
224            params.append(self.src_dir)
225            params.append(f'./{get_file_name(self.definitions_module_name)}')
226            if self.additional_go_packages:
227                params.extend(self.additional_go_packages)
228                
229            compiler_output: str = str()
230            with change_current_dir(self.dir_path):
231                self._ensure_gitignore()
232                self._generate_definitions_module()
233                print('> Go compiler command line:')
234                print(prepare_command(params[0], params[1:]))
235                print('> Go compiler params:')
236                pprint(params)
237                print('> Additional environmental variables:')
238                pprint(additional_env)
239                result = subprocess.run(params, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
240                compiler_output = result.stdout
241
242            successed: bool = find_text(compiler_output, 'cmd had error:') is None
243            print(f'{successed=}')
244            print('> Go compiler output:')
245            print(compiler_output)
246            exported_files_list = self._exported_files_list()
247            adjusted_exported_files_list = list()
248            for file_path in exported_files_list:
249                adjusted_exported_files_list.append(get_relative_path_part(file_path, self.dir_path))
250            
251            if successed:
252                print('> Exported files:')
253                print(adjusted_exported_files_list)
254            
255            print('==================================================')
256            # raise RuntimeError
257            return adjusted_exported_files_list if successed else None
258        except:
259            print('==================================================')
260            print('!!! GO COMPILATION EXCEPTION !!!')
261            print('==================================================')
262            print(exception_to_printable_text(get_exception()))
263            print('==================================================')
264            return None
265    
266    def sdist(self) -> Optional[List[str]]:
267        src_dir_path: str = RelativePath(self.dir_path)(self._src_dir)
268        def filter(entity: FilteringEntity, data: Any):
269            if FilteringEntity.filename == entity:
270                dirpath, filename = data
271                if filename in {
272                    '__init__.py', 
273                    '__x__build_config.py', 
274                    '__build_config.py', 
275                }:
276                    return False
277                
278                if last_ext(filename) in {'so', 'dylib', 'pyd', 'dll', 'py', 'pyw', 'gitignore', 'pyc'}:
279                    return False
280
281                return True
282            elif FilteringEntity.dirname == entity:
283                dirpath, dirname = data
284                if dirname in {
285                    '__pycache__', 
286                    }:
287                    return False
288
289                return True
290            elif FilteringEntity.dirpath == entity:
291                dirpath, dirnames, filenames = data
292                dirpath_basename = basename(dirpath)
293                if dirpath_basename in {
294                    '__pycache__', 
295                    }:
296                    return False
297                
298                return True
299            elif FilteringEntity.aggregated == entity:
300                result_full_file_names: List[str] = list()
301                for dirpath, new_dirnames, new_filenames in data:
302                    for file_name in new_filenames:
303                        result_full_file_names.append(path_join(dirpath, file_name))
304                
305                return result_full_file_names
306            else:
307                raise NotImplementedError
308
309        result_full_file_names: List[str] = file_list_traversal_ex(src_dir_path, filter, True)
310        go_module_setup_files = [
311            'go.mod', 
312            'go.sum', 
313        ]
314        adjusted_exported_files_list = list()
315        for file_name in go_module_setup_files:
316            if file_exists(path_join(self.dir_path, file_name)):
317                adjusted_exported_files_list.append(file_name)
318        
319        for file_path in result_full_file_names:
320            adjusted_exported_files_list.append(get_relative_path_part(file_path, self.dir_path))
321        
322        return adjusted_exported_files_list
323    
324    def _exported_files_list(self) -> List[str]:
325        def filter(data_type: FilteringEntity, data):
326            if FilteringEntity.dirpath == data_type:
327                return True
328            elif FilteringEntity.dirname == data_type:
329                return False
330            elif FilteringEntity.filename == data_type:
331                _, file_name = data
332                if file_name in {'__init__.py', 'go.py'}:
333                    return True
334                elif file_name in {'build.py', 'Makefile'}:
335                    return False
336                elif last_ext(file_name) in {'so', 'dylib', 'pyd', 'dll', 'py', 'pyw'}:
337                    return True
338                else:
339                    return False
340            elif FilteringEntity.aggregated == data_type:
341                result_full_file_names: List[str] = list()
342                for dirpath, new_dirnames, new_filenames in data:
343                    for file_name in new_filenames:
344                        result_full_file_names.append(path_join(dirpath, file_name))
345                
346                return result_full_file_names
347            else:
348                raise NotImplementedError
349        
350        result_full_file_names: List[str] = file_list_traversal(self.out_dir, filter, True)
351        return result_full_file_names if result_full_file_names else None
352
353    def _ensure_gitignore(self):
354        gitignore_path = self.dir_path_rel('.gitignore')
355        if file_exists(gitignore_path):
356            with open(gitignore_path, 'r+t') as f:
357                content = f.read()
358                if self.definitions_module_name not in content:
359                    f.write(f'{self.definitions_module_name}/\n')
360                
361                out_dir_name = basename(self.out_dir)
362                out_dir_name_ignorable = f'{out_dir_name}/'
363                if out_dir_name_ignorable not in content:
364                    f.write(f'{out_dir_name_ignorable}\n')
365
366                # if 'go.mod' not in content:
367                #     f.write(f'go.mod\n')
368
369                # if 'go.sum' not in content:
370                #     f.write(f'go.sum\n')
371        else:
372            with open(gitignore_path, 'xt') as f:
373                f.write(f'{self.definitions_module_name}/\n')
374                out_dir_name = basename(self.out_dir)
375                out_dir_name_ignorable = f'{out_dir_name}/'
376                f.write(f'{out_dir_name_ignorable}\n')
377                # f.write(f'go.mod\n')
378                # f.write(f'go.sum\n')
379    
380    def _generate_definitions_module(self):
381        file_content_template: str = """// {config_file_name}
382package {config_module_name}
383
384const (
385{constants_text}
386)
387"""
388        constants_strings: List[str] = list()
389        for name, value in self.result_definitions.items():
390            prepared_value = prepare_definition_value_f(value)
391            if prepared_value is None:
392                continue
393            
394            constants_strings.append(f'\t{name} = {prepared_value}')
395        
396        constants_text: str = '\n'.join(constants_strings)
397        file_content: str = file_content_template.format(
398            config_file_name=self.definitions_module_file_name,
399            config_module_name=get_file_name(self.definitions_module_name),
400            constants_text=constants_text,
401        )
402
403        definitions_module_dir = self.dir_path_rel(self.definitions_module_name)
404        ensure_dir(definitions_module_dir)
405        definitions_module_dir_rel = RelativePath(definitions_module_dir)
406        with open(self.dir_path_rel(definitions_module_dir_rel(self.definitions_module_file_name)), 'wt') as f:
407            f.write(file_content)
class CengalGoBuildExtension(cengal.build_tools.build_extensions.versions.v_0.build_extensions.CengalBuildExtension):
150class CengalGoBuildExtension(CengalBuildExtension):
151    base_class: Optional[Type] = None
152    store_as_data: bool = True
153
154    def __init__(self, 
155                 module_name: Optional[str] = None, 
156                 src_dir: str = './src',
157                 out_dir_name: str = 'compiled',
158                 flags: Optional[List[str]] = None, 
159                 definitions: Optional[Union[Sequence[str], Dict[str, Union[Union[None, bool, int, str], Tuple[bool, Union[None, bool, str, int]]]]]] = None, 
160                 additional_build_params: Optional[List[str]] = None, 
161                 additional_go_packages: Optional[List[str]] = None, 
162                 definitions_module_name: str = 'compile_time_py_definitions', 
163                 **kwargs) -> None:
164        super().__init__(kwargs)
165        self.module_name: str = module_name
166        self.out_dir_name: str = out_dir_name
167        self._src_dir: str = src_dir
168        self.src_dir: str = None
169        self.out_dir: str = None
170        self.flags: Optional[List[str]] = flags or list()
171        self.definitions: Optional[Union[Sequence[str], Dict[str, Union[Union[None, bool, int, str], Tuple[bool, Union[None, bool, str, int]]]]]] = definitions or dict()
172        result_flags = adjust_definition_names(list_to_dict(prepare_compile_time_flags()), 'GOF_', 'GOD_')  # GOF is Go Flag; GOD is Go Definition
173        self.result_definitions: Optional[Dict[str, Union[None, bool, int, float, str]]] = adjust_definition_names(prepare_compile_time_env(), 'GOF_', 'GOD_')  # GOF is Go Flag; GOD is Go Definition
174        self.result_definitions.update(result_flags)
175        self.result_definitions.update(dict_of_tuples_to_dict(list_to_dict(definitions)))
176        self.result_definitions.update(list_to_dict(flags))
177        self.additional_build_params: Optional[List[str]] = additional_build_params
178        self.additional_go_packages: Optional[List[str]] = additional_go_packages
179        self.definitions_module_name: str = definitions_module_name
180        self.definitions_module_file_name: str = f'{definitions_module_name}.go'
181    
182    @property
183    def module_name_str(self):
184        if self.module_name:
185            return self.module_name
186        else:
187            namespace = self.name
188            namespace_parts = namespace.split('.')
189            return'/'.join(namespace_parts[:-1])
190    
191    def __call__(self):
192        try:
193            # self.src_dir: str = self._src_dir if os.path.isabs(self._src_dir) else RelativePath(self.dir_path)(self._src_dir)
194            self.src_dir: str = self._src_dir
195            self.out_dir: str = RelativePath(self.dir_path)(self.out_dir_name)
196            print()
197            print('==================================================')
198            print(f'<<< GO COMPILATION: {self.module_name_str} >>>')
199            print('=======================')
200            go_module_setup_files = [
201                'go.mod', 
202                'go.sum', 
203            ]
204            adjusted_exported_files_list = list()
205            need_to_init_go_module = False
206            for file_name in go_module_setup_files:
207                if not file_exists(path_join(self.dir_path, file_name)):
208                    need_to_init_go_module = True
209                    break
210            
211            if need_to_init_go_module:
212                with change_current_dir(self.dir_path):
213                    params = ['go', 'mod', 'init', self.module_name_str]
214                    result = subprocess.run(params, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
215                    print(result.stdout)
216
217            env = os.environ.copy()
218            additional_env = dict()
219            additional_env['LD_LIBRARY_PATH'] = f"{env.get('LD_LIBRARY_PATH', '')}{os.pathsep}."
220            env.update(additional_env)
221            params = ['gopy', 'build', f'-output={self.out_dir_name}', f'-vm={sys.executable}']
222            if self.additional_build_params:
223                params.extend(self.additional_build_params)
224            
225            params.append(self.src_dir)
226            params.append(f'./{get_file_name(self.definitions_module_name)}')
227            if self.additional_go_packages:
228                params.extend(self.additional_go_packages)
229                
230            compiler_output: str = str()
231            with change_current_dir(self.dir_path):
232                self._ensure_gitignore()
233                self._generate_definitions_module()
234                print('> Go compiler command line:')
235                print(prepare_command(params[0], params[1:]))
236                print('> Go compiler params:')
237                pprint(params)
238                print('> Additional environmental variables:')
239                pprint(additional_env)
240                result = subprocess.run(params, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
241                compiler_output = result.stdout
242
243            successed: bool = find_text(compiler_output, 'cmd had error:') is None
244            print(f'{successed=}')
245            print('> Go compiler output:')
246            print(compiler_output)
247            exported_files_list = self._exported_files_list()
248            adjusted_exported_files_list = list()
249            for file_path in exported_files_list:
250                adjusted_exported_files_list.append(get_relative_path_part(file_path, self.dir_path))
251            
252            if successed:
253                print('> Exported files:')
254                print(adjusted_exported_files_list)
255            
256            print('==================================================')
257            # raise RuntimeError
258            return adjusted_exported_files_list if successed else None
259        except:
260            print('==================================================')
261            print('!!! GO COMPILATION EXCEPTION !!!')
262            print('==================================================')
263            print(exception_to_printable_text(get_exception()))
264            print('==================================================')
265            return None
266    
267    def sdist(self) -> Optional[List[str]]:
268        src_dir_path: str = RelativePath(self.dir_path)(self._src_dir)
269        def filter(entity: FilteringEntity, data: Any):
270            if FilteringEntity.filename == entity:
271                dirpath, filename = data
272                if filename in {
273                    '__init__.py', 
274                    '__x__build_config.py', 
275                    '__build_config.py', 
276                }:
277                    return False
278                
279                if last_ext(filename) in {'so', 'dylib', 'pyd', 'dll', 'py', 'pyw', 'gitignore', 'pyc'}:
280                    return False
281
282                return True
283            elif FilteringEntity.dirname == entity:
284                dirpath, dirname = data
285                if dirname in {
286                    '__pycache__', 
287                    }:
288                    return False
289
290                return True
291            elif FilteringEntity.dirpath == entity:
292                dirpath, dirnames, filenames = data
293                dirpath_basename = basename(dirpath)
294                if dirpath_basename in {
295                    '__pycache__', 
296                    }:
297                    return False
298                
299                return True
300            elif FilteringEntity.aggregated == entity:
301                result_full_file_names: List[str] = list()
302                for dirpath, new_dirnames, new_filenames in data:
303                    for file_name in new_filenames:
304                        result_full_file_names.append(path_join(dirpath, file_name))
305                
306                return result_full_file_names
307            else:
308                raise NotImplementedError
309
310        result_full_file_names: List[str] = file_list_traversal_ex(src_dir_path, filter, True)
311        go_module_setup_files = [
312            'go.mod', 
313            'go.sum', 
314        ]
315        adjusted_exported_files_list = list()
316        for file_name in go_module_setup_files:
317            if file_exists(path_join(self.dir_path, file_name)):
318                adjusted_exported_files_list.append(file_name)
319        
320        for file_path in result_full_file_names:
321            adjusted_exported_files_list.append(get_relative_path_part(file_path, self.dir_path))
322        
323        return adjusted_exported_files_list
324    
325    def _exported_files_list(self) -> List[str]:
326        def filter(data_type: FilteringEntity, data):
327            if FilteringEntity.dirpath == data_type:
328                return True
329            elif FilteringEntity.dirname == data_type:
330                return False
331            elif FilteringEntity.filename == data_type:
332                _, file_name = data
333                if file_name in {'__init__.py', 'go.py'}:
334                    return True
335                elif file_name in {'build.py', 'Makefile'}:
336                    return False
337                elif last_ext(file_name) in {'so', 'dylib', 'pyd', 'dll', 'py', 'pyw'}:
338                    return True
339                else:
340                    return False
341            elif FilteringEntity.aggregated == data_type:
342                result_full_file_names: List[str] = list()
343                for dirpath, new_dirnames, new_filenames in data:
344                    for file_name in new_filenames:
345                        result_full_file_names.append(path_join(dirpath, file_name))
346                
347                return result_full_file_names
348            else:
349                raise NotImplementedError
350        
351        result_full_file_names: List[str] = file_list_traversal(self.out_dir, filter, True)
352        return result_full_file_names if result_full_file_names else None
353
354    def _ensure_gitignore(self):
355        gitignore_path = self.dir_path_rel('.gitignore')
356        if file_exists(gitignore_path):
357            with open(gitignore_path, 'r+t') as f:
358                content = f.read()
359                if self.definitions_module_name not in content:
360                    f.write(f'{self.definitions_module_name}/\n')
361                
362                out_dir_name = basename(self.out_dir)
363                out_dir_name_ignorable = f'{out_dir_name}/'
364                if out_dir_name_ignorable not in content:
365                    f.write(f'{out_dir_name_ignorable}\n')
366
367                # if 'go.mod' not in content:
368                #     f.write(f'go.mod\n')
369
370                # if 'go.sum' not in content:
371                #     f.write(f'go.sum\n')
372        else:
373            with open(gitignore_path, 'xt') as f:
374                f.write(f'{self.definitions_module_name}/\n')
375                out_dir_name = basename(self.out_dir)
376                out_dir_name_ignorable = f'{out_dir_name}/'
377                f.write(f'{out_dir_name_ignorable}\n')
378                # f.write(f'go.mod\n')
379                # f.write(f'go.sum\n')
380    
381    def _generate_definitions_module(self):
382        file_content_template: str = """// {config_file_name}
383package {config_module_name}
384
385const (
386{constants_text}
387)
388"""
389        constants_strings: List[str] = list()
390        for name, value in self.result_definitions.items():
391            prepared_value = prepare_definition_value_f(value)
392            if prepared_value is None:
393                continue
394            
395            constants_strings.append(f'\t{name} = {prepared_value}')
396        
397        constants_text: str = '\n'.join(constants_strings)
398        file_content: str = file_content_template.format(
399            config_file_name=self.definitions_module_file_name,
400            config_module_name=get_file_name(self.definitions_module_name),
401            constants_text=constants_text,
402        )
403
404        definitions_module_dir = self.dir_path_rel(self.definitions_module_name)
405        ensure_dir(definitions_module_dir)
406        definitions_module_dir_rel = RelativePath(definitions_module_dir)
407        with open(self.dir_path_rel(definitions_module_dir_rel(self.definitions_module_file_name)), 'wt') as f:
408            f.write(file_content)
CengalGoBuildExtension( module_name: Union[str, NoneType] = None, src_dir: str = './src', out_dir_name: str = 'compiled', flags: Union[List[str], NoneType] = None, definitions: Union[Sequence[str], Dict[str, Union[NoneType, bool, int, str, Tuple[bool, Union[NoneType, bool, str, int]]]], NoneType] = None, additional_build_params: Union[List[str], NoneType] = None, additional_go_packages: Union[List[str], NoneType] = None, definitions_module_name: str = 'compile_time_py_definitions', **kwargs)
154    def __init__(self, 
155                 module_name: Optional[str] = None, 
156                 src_dir: str = './src',
157                 out_dir_name: str = 'compiled',
158                 flags: Optional[List[str]] = None, 
159                 definitions: Optional[Union[Sequence[str], Dict[str, Union[Union[None, bool, int, str], Tuple[bool, Union[None, bool, str, int]]]]]] = None, 
160                 additional_build_params: Optional[List[str]] = None, 
161                 additional_go_packages: Optional[List[str]] = None, 
162                 definitions_module_name: str = 'compile_time_py_definitions', 
163                 **kwargs) -> None:
164        super().__init__(kwargs)
165        self.module_name: str = module_name
166        self.out_dir_name: str = out_dir_name
167        self._src_dir: str = src_dir
168        self.src_dir: str = None
169        self.out_dir: str = None
170        self.flags: Optional[List[str]] = flags or list()
171        self.definitions: Optional[Union[Sequence[str], Dict[str, Union[Union[None, bool, int, str], Tuple[bool, Union[None, bool, str, int]]]]]] = definitions or dict()
172        result_flags = adjust_definition_names(list_to_dict(prepare_compile_time_flags()), 'GOF_', 'GOD_')  # GOF is Go Flag; GOD is Go Definition
173        self.result_definitions: Optional[Dict[str, Union[None, bool, int, float, str]]] = adjust_definition_names(prepare_compile_time_env(), 'GOF_', 'GOD_')  # GOF is Go Flag; GOD is Go Definition
174        self.result_definitions.update(result_flags)
175        self.result_definitions.update(dict_of_tuples_to_dict(list_to_dict(definitions)))
176        self.result_definitions.update(list_to_dict(flags))
177        self.additional_build_params: Optional[List[str]] = additional_build_params
178        self.additional_go_packages: Optional[List[str]] = additional_go_packages
179        self.definitions_module_name: str = definitions_module_name
180        self.definitions_module_file_name: str = f'{definitions_module_name}.go'
base_class: Union[Type, NoneType] = None
store_as_data: bool = True
module_name: str
out_dir_name: str
src_dir: str
out_dir: str
flags: Union[List[str], NoneType]
definitions: Union[Sequence[str], Dict[str, Union[NoneType, bool, int, str, Tuple[bool, Union[NoneType, bool, str, int]]]], NoneType]
result_definitions: Union[Dict[str, Union[NoneType, bool, int, float, str]], NoneType]
additional_build_params: Union[List[str], NoneType]
additional_go_packages: Union[List[str], NoneType]
definitions_module_name: str
definitions_module_file_name: str
module_name_str
182    @property
183    def module_name_str(self):
184        if self.module_name:
185            return self.module_name
186        else:
187            namespace = self.name
188            namespace_parts = namespace.split('.')
189            return'/'.join(namespace_parts[:-1])
def sdist(self) -> Union[List[str], NoneType]:
267    def sdist(self) -> Optional[List[str]]:
268        src_dir_path: str = RelativePath(self.dir_path)(self._src_dir)
269        def filter(entity: FilteringEntity, data: Any):
270            if FilteringEntity.filename == entity:
271                dirpath, filename = data
272                if filename in {
273                    '__init__.py', 
274                    '__x__build_config.py', 
275                    '__build_config.py', 
276                }:
277                    return False
278                
279                if last_ext(filename) in {'so', 'dylib', 'pyd', 'dll', 'py', 'pyw', 'gitignore', 'pyc'}:
280                    return False
281
282                return True
283            elif FilteringEntity.dirname == entity:
284                dirpath, dirname = data
285                if dirname in {
286                    '__pycache__', 
287                    }:
288                    return False
289
290                return True
291            elif FilteringEntity.dirpath == entity:
292                dirpath, dirnames, filenames = data
293                dirpath_basename = basename(dirpath)
294                if dirpath_basename in {
295                    '__pycache__', 
296                    }:
297                    return False
298                
299                return True
300            elif FilteringEntity.aggregated == entity:
301                result_full_file_names: List[str] = list()
302                for dirpath, new_dirnames, new_filenames in data:
303                    for file_name in new_filenames:
304                        result_full_file_names.append(path_join(dirpath, file_name))
305                
306                return result_full_file_names
307            else:
308                raise NotImplementedError
309
310        result_full_file_names: List[str] = file_list_traversal_ex(src_dir_path, filter, True)
311        go_module_setup_files = [
312            'go.mod', 
313            'go.sum', 
314        ]
315        adjusted_exported_files_list = list()
316        for file_name in go_module_setup_files:
317            if file_exists(path_join(self.dir_path, file_name)):
318                adjusted_exported_files_list.append(file_name)
319        
320        for file_path in result_full_file_names:
321            adjusted_exported_files_list.append(get_relative_path_part(file_path, self.dir_path))
322        
323        return adjusted_exported_files_list
Inherited Members
cengal.build_tools.build_extensions.versions.v_0.build_extensions.CengalBuildExtension
kwargs
path
dir_path
dir_path_rel
module_import_str
name
package
files