omdev 0.0.0.dev11__tar.gz → 0.0.0.dev13__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. omdev-0.0.0.dev13/PKG-INFO +32 -0
  2. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/__about__.py +9 -5
  3. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/amalg/amalg.py +13 -1
  4. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/cmake.py +1 -2
  5. omdev-0.0.0.dev13/omdev/exts/cmake.py +342 -0
  6. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/scan.py +2 -2
  7. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/scripts/findmagic.py +5 -2
  8. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/scripts/interp.py +5 -0
  9. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/scripts/pyproject.py +7 -0
  10. omdev-0.0.0.dev13/omdev/tools/revisions.py +173 -0
  11. omdev-0.0.0.dev13/omdev/wheelfile.py +246 -0
  12. omdev-0.0.0.dev13/omdev.egg-info/PKG-INFO +32 -0
  13. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev.egg-info/SOURCES.txt +2 -0
  14. omdev-0.0.0.dev13/omdev.egg-info/requires.txt +23 -0
  15. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/pyproject.toml +17 -13
  16. omdev-0.0.0.dev11/PKG-INFO +0 -29
  17. omdev-0.0.0.dev11/omdev/exts/cmake.py +0 -208
  18. omdev-0.0.0.dev11/omdev.egg-info/PKG-INFO +0 -29
  19. omdev-0.0.0.dev11/omdev.egg-info/requires.txt +0 -19
  20. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/LICENSE +0 -0
  21. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/MANIFEST.in +0 -0
  22. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/README.rst +0 -0
  23. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/__init__.py +0 -0
  24. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/amalg/__init__.py +0 -0
  25. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/amalg/__main__.py +0 -0
  26. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/classdot.py +0 -0
  27. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/__init__.py +0 -0
  28. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/__init__.py +0 -0
  29. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/build_ext.py +0 -0
  30. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/compilers/__init__.py +0 -0
  31. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/compilers/ccompiler.py +0 -0
  32. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/compilers/options.py +0 -0
  33. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/compilers/unixccompiler.py +0 -0
  34. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/dir_util.py +0 -0
  35. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/errors.py +0 -0
  36. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/extension.py +0 -0
  37. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/file_util.py +0 -0
  38. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/modified.py +0 -0
  39. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/spawn.py +0 -0
  40. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/sysconfig.py +0 -0
  41. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/util.py +0 -0
  42. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/_distutils/version.py +0 -0
  43. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/build.py +0 -0
  44. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/exts/importhook.py +0 -0
  45. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/interp/__init__.py +0 -0
  46. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/interp/__main__.py +0 -0
  47. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/interp/cli.py +0 -0
  48. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/interp/inspect.py +0 -0
  49. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/interp/providers.py +0 -0
  50. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/interp/pyenv.py +0 -0
  51. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/interp/resolvers.py +0 -0
  52. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/interp/standalone.py +0 -0
  53. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/interp/system.py +0 -0
  54. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/interp/types.py +0 -0
  55. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/mypy/__init__.py +0 -0
  56. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/mypy/debug.py +0 -0
  57. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/pyproject/__init__.py +0 -0
  58. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/pyproject/__main__.py +0 -0
  59. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/pyproject/cli.py +0 -0
  60. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/pyproject/configs.py +0 -0
  61. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/pyproject/ext.py +0 -0
  62. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/pyproject/pkg.py +0 -0
  63. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/scripts/__init__.py +0 -0
  64. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/scripts/bracepy.py +0 -0
  65. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/scripts/execrss.py +0 -0
  66. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/scripts/findimports.py +0 -0
  67. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/scripts/traceimport.py +0 -0
  68. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/tokens.py +0 -0
  69. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/toml/__init__.py +0 -0
  70. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/toml/parser.py +0 -0
  71. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/toml/writer.py +0 -0
  72. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/tools/__init__.py +0 -0
  73. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/tools/dockertools.py +0 -0
  74. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/tools/gittools.py +0 -0
  75. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/tools/sqlrepl.py +0 -0
  76. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/versioning/__init__.py +0 -0
  77. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/versioning/specifiers.py +0 -0
  78. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev/versioning/versions.py +0 -0
  79. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev.egg-info/dependency_links.txt +0 -0
  80. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/omdev.egg-info/top_level.txt +0 -0
  81. {omdev-0.0.0.dev11 → omdev-0.0.0.dev13}/setup.cfg +0 -0
@@ -0,0 +1,32 @@
1
+ Metadata-Version: 2.1
2
+ Name: omdev
3
+ Version: 0.0.0.dev13
4
+ Summary: omdev
5
+ Author: wrmsr
6
+ License: BSD-3-Clause
7
+ Project-URL: source, https://github.com/wrmsr/omlish
8
+ Classifier: License :: OSI Approved :: BSD License
9
+ Classifier: Development Status :: 2 - Pre-Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Operating System :: POSIX
13
+ Requires-Python: ~=3.12
14
+ License-File: LICENSE
15
+ Requires-Dist: omlish==0.0.0.dev13
16
+ Provides-Extra: all
17
+ Requires-Dist: pycparser~=2.22; extra == "all"
18
+ Requires-Dist: cffi~=1.17; extra == "all"
19
+ Requires-Dist: pcpp~=1.30; extra == "all"
20
+ Requires-Dist: mypy~=1.11; extra == "all"
21
+ Requires-Dist: tokenize_rt~=6.0; extra == "all"
22
+ Requires-Dist: wheel~=0.44; extra == "all"
23
+ Provides-Extra: c
24
+ Requires-Dist: pycparser~=2.22; extra == "c"
25
+ Requires-Dist: cffi~=1.17; extra == "c"
26
+ Requires-Dist: pcpp~=1.30; extra == "c"
27
+ Provides-Extra: mypy
28
+ Requires-Dist: mypy~=1.11; extra == "mypy"
29
+ Provides-Extra: tokens
30
+ Requires-Dist: tokenize_rt~=6.0; extra == "tokens"
31
+ Provides-Extra: wheel
32
+ Requires-Dist: wheel~=0.44; extra == "wheel"
@@ -13,17 +13,21 @@ class Project(ProjectBase):
13
13
 
14
14
  optional_dependencies = {
15
15
  'c': [
16
- 'pycparser >= 2.22',
17
- 'cffi >= 1.17',
18
- 'pcpp >= 1.30',
16
+ 'pycparser ~= 2.22',
17
+ 'cffi ~= 1.17',
18
+ 'pcpp ~= 1.30',
19
19
  ],
20
20
 
21
21
  'mypy': [
22
- 'mypy >= 1.11',
22
+ 'mypy ~= 1.11',
23
23
  ],
24
24
 
25
25
  'tokens': [
26
- 'tokenize_rt >= 6',
26
+ 'tokenize_rt ~= 6.0',
27
+ ],
28
+
29
+ 'wheel': [
30
+ 'wheel ~= 0.44',
27
31
  ],
28
32
  }
29
33
 
@@ -363,13 +363,25 @@ def gen_amalg(
363
363
 
364
364
  ##
365
365
 
366
+ tyd: dict[str, list[Typing]] = {}
366
367
  tys = set()
367
368
  for sf in sfs:
368
369
  f = src_files[sf]
369
370
  for ty in f.typings:
370
371
  if ty.src not in tys:
371
- out.write(ty.src)
372
+ tyd.setdefault(f.path, []).append(ty)
372
373
  tys.add(ty.src)
374
+ for i, (sf, ftys) in enumerate(tyd.items()):
375
+ f = src_files[sf]
376
+ if i:
377
+ out.write('\n')
378
+ if f is not mf:
379
+ rp = os.path.relpath(f.path, mf.path)
380
+ else:
381
+ rp = os.path.basename(f.path)
382
+ out.write(f'# {rp}\n')
383
+ for ty in ftys:
384
+ out.write(ty.src)
373
385
  if tys:
374
386
  out.write('\n\n')
375
387
 
@@ -1,5 +1,4 @@
1
1
  import abc
2
- import io
3
2
  import typing as ta
4
3
 
5
4
  from omlish import dataclasses as dc
@@ -80,7 +79,7 @@ class CmakeGen:
80
79
 
81
80
  def __init__(
82
81
  self,
83
- out: io.TextIOBase,
82
+ out: ta.TextIO,
84
83
  *,
85
84
  indent: int = 4,
86
85
  ) -> None:
@@ -0,0 +1,342 @@
1
+ """
2
+ TODO:
3
+ - symlink headers, included src files (hamt_impl, ...)
4
+ - point / copy output to dst dirs
5
+ - libs
6
+ - ..
7
+ - pybind
8
+ - catch2?
9
+ - json? https://github.com/nlohmann/json
10
+ - FindPackages? FetchContent? built_ext won't have that
11
+ - move omml git / data retriever stuff into omdev, get just the one header file from git via sha?
12
+ - support local built pys
13
+
14
+ ==
15
+
16
+ Done:
17
+ - https://intellij-support.jetbrains.com/hc/en-us/community/posts/206608485-Multiple-Jetbrain-IDE-sharing-the-same-project-directory really?
18
+ - aight, generate a whole cmake subdir with symlinks to src files lol
19
+
20
+ """ # noqa
21
+ import argparse
22
+ import dataclasses as dc
23
+ import io
24
+ import logging
25
+ import os.path
26
+ import shutil
27
+ import sys
28
+ import sysconfig
29
+ import typing as ta
30
+
31
+ from omlish import check
32
+ from omlish import lang
33
+ from omlish import logs
34
+
35
+ from .. import cmake
36
+ from ..scripts import findmagic
37
+
38
+
39
+ log = logging.getLogger(__name__)
40
+
41
+
42
+ ##
43
+
44
+
45
+ MAGIC = '@omdev-ext'
46
+ MAGIC_COMMENT = f'// {MAGIC}'
47
+
48
+ FILE_EXTENSIONS = ('c', 'cc', 'cpp')
49
+
50
+
51
+ def _sep_str_grps(*ls: ta.Sequence[str]) -> list[str]:
52
+ o = []
53
+ for i, l in enumerate(ls):
54
+ if not l:
55
+ continue
56
+ if i:
57
+ o.append('')
58
+ o.extend(check.not_isinstance(l, str))
59
+ return o
60
+
61
+
62
+ class CmakeProjectGen:
63
+ def __init__(
64
+ self,
65
+ exts: ta.Sequence[str],
66
+ prj_root: str | None = None,
67
+ ) -> None:
68
+ super().__init__()
69
+ self._exts = check.not_isinstance(exts, str)
70
+ self._prj_root = os.path.abspath(prj_root) if prj_root is not None else os.getcwd()
71
+
72
+ #
73
+
74
+ @property
75
+ def prj_root(self) -> str:
76
+ return self._prj_root
77
+
78
+ @lang.cached_function
79
+ def prj_name(self) -> str:
80
+ return os.path.basename(self.prj_root)
81
+
82
+ @lang.cached_function
83
+ def cmake_dir(self) -> str:
84
+ cmake_dir = os.path.join(self.prj_root, 'cmake')
85
+ if os.path.exists(cmake_dir):
86
+ for e in os.listdir(cmake_dir):
87
+ if e == '.idea':
88
+ continue
89
+ ep = os.path.join(cmake_dir, e)
90
+ if os.path.isfile(ep):
91
+ os.unlink(ep)
92
+ else:
93
+ shutil.rmtree(ep)
94
+ else:
95
+ os.mkdir(cmake_dir)
96
+ return cmake_dir
97
+
98
+ #
99
+
100
+ def write_git_ignore(self) -> None:
101
+ with open(os.path.join(self.cmake_dir(), '.gitignore'), 'w') as f:
102
+ f.write('\n'.join(sorted(['/cmake-*', '/build'])))
103
+
104
+ #
105
+
106
+ def write_idea_name(self) -> None:
107
+ idea_dir = os.path.join(self.cmake_dir(), '.idea')
108
+ if not os.path.isdir(idea_dir):
109
+ os.mkdir(idea_dir)
110
+ idea_name_file = os.path.join(idea_dir, '.name')
111
+ if not os.path.isfile(idea_name_file):
112
+ with open(idea_name_file, 'w') as f:
113
+ f.write(self.prj_name())
114
+
115
+ #
116
+
117
+ @dc.dataclass(frozen=True, kw_only=True)
118
+ class PyInfo:
119
+ venv_exe: str
120
+ venv_root: str
121
+ real_exe: str
122
+ root: str
123
+ suffix: str
124
+
125
+ @lang.cached_function
126
+ def py_info(self) -> PyInfo:
127
+ venv_exe = sys.executable
128
+ real_exe = os.path.realpath(venv_exe)
129
+ return self.PyInfo(
130
+ venv_exe=venv_exe,
131
+ venv_root=os.path.abspath(os.path.join(os.path.dirname(venv_exe), '..')),
132
+ real_exe=real_exe,
133
+ root=os.path.abspath(os.path.join(os.path.dirname(real_exe), '..')),
134
+ suffix='.'.join(map(str, sys.version_info[:2])),
135
+ )
136
+
137
+ #
138
+
139
+ @lang.cached_function
140
+ def ext_files(self) -> ta.Sequence[str]:
141
+ out = []
142
+ for e in self._exts:
143
+ e = os.path.abspath(e)
144
+ if os.path.isfile(e):
145
+ out.append(e)
146
+ elif os.path.isdir(e):
147
+ out.extend(
148
+ findmagic.find_magic(
149
+ [e],
150
+ [MAGIC_COMMENT],
151
+ FILE_EXTENSIONS,
152
+ ),
153
+ )
154
+ else:
155
+ raise KeyError(e)
156
+ return out
157
+
158
+ #
159
+
160
+ class _CmakeListsGen:
161
+ def __init__(
162
+ self,
163
+ p: 'CmakeProjectGen',
164
+ out: ta.TextIO,
165
+ ) -> None:
166
+ super().__init__()
167
+ self.p = p
168
+ self.g = cmake.CmakeGen(out)
169
+
170
+ @lang.cached_property
171
+ def var_prefix(self) -> str:
172
+ return self.p.prj_name().upper()
173
+
174
+ @lang.cached_property
175
+ def py(self) -> 'CmakeProjectGen.PyInfo':
176
+ return self.p.py_info()
177
+
178
+ def _add_ext(self, ext_src: str) -> None:
179
+ ext_name = ext_src.rpartition('.')[0].replace('/', '__')
180
+
181
+ log.info('Adding cmake c extension: %s -> %s', ext_src, ext_name)
182
+
183
+ so_name = ''.join([
184
+ os.path.basename(ext_src).split('.')[0],
185
+ '.',
186
+ sysconfig.get_config_var('SOABI'),
187
+ sysconfig.get_config_var('SHLIB_SUFFIX'),
188
+ ])
189
+
190
+ sl = os.path.join(self.p.cmake_dir(), ext_src)
191
+ sal = os.path.abspath(sl)
192
+ sd = os.path.dirname(sal)
193
+ os.makedirs(sd, exist_ok=True)
194
+ rp = os.path.relpath(os.path.abspath(ext_src), sd)
195
+ os.symlink(rp, sal)
196
+
197
+ ml = cmake.ModuleLibrary(
198
+ ext_name,
199
+ src_files=[
200
+ sl,
201
+ ],
202
+ include_dirs=[
203
+ f'${{{self.var_prefix}_INCLUDE_DIRECTORIES}}',
204
+ ],
205
+ compile_opts=[
206
+ f'${{{self.var_prefix}_COMPILE_OPTIONS}}',
207
+ ],
208
+ link_dirs=[
209
+ f'${{{self.var_prefix}_LINK_DIRECTORIES}}',
210
+ ],
211
+ link_libs=[
212
+ f'${{{self.var_prefix}_LINK_LIBRARIES}}',
213
+ ],
214
+ extra_cmds=[
215
+ cmake.Command(
216
+ 'add_custom_command',
217
+ ['TARGET', ext_name, 'POST_BUILD'],
218
+ [
219
+ ' '.join([
220
+ 'COMMAND ${CMAKE_COMMAND} -E ',
221
+ f'copy $<TARGET_FILE_NAME:{ext_name}> ../../{os.path.dirname(ext_src)}/{so_name}',
222
+ ]),
223
+ 'COMMAND_EXPAND_LISTS',
224
+ ],
225
+ ),
226
+ ],
227
+ )
228
+ self.g.write_target(ml)
229
+
230
+ def run(self) -> None:
231
+ self.g.write(self.g.preamble)
232
+ self.g.write('')
233
+
234
+ self.g.write(f'project({self.p.prj_name()})')
235
+ self.g.write('')
236
+
237
+ self.g.write_var(cmake.Var(
238
+ f'{self.var_prefix}_INCLUDE_DIRECTORIES',
239
+ _sep_str_grps(
240
+ [f'{self.py.venv_root}/include'],
241
+ [f'{self.py.root}/include/python{self.py.suffix}'],
242
+ [
243
+ # $ENV{HOME}/src/python/cpython
244
+ # $ENV{HOME}/src/python/cpython/include
245
+ ],
246
+ ),
247
+ ))
248
+
249
+ self.g.write_var(cmake.Var(
250
+ f'{self.var_prefix}_COMPILE_OPTIONS',
251
+ _sep_str_grps(
252
+ [
253
+ '-Wsign-compare',
254
+ '-Wunreachable-code',
255
+ '-DNDEBUG',
256
+ '-g',
257
+ '-fwrapv',
258
+ '-O3',
259
+ '-Wall',
260
+ ],
261
+ [
262
+ '-g',
263
+ '-c',
264
+ ],
265
+ ['-std=c++20'],
266
+ ),
267
+ ))
268
+
269
+ self.g.write_var(cmake.Var(
270
+ f'{self.var_prefix}_LINK_DIRECTORIES',
271
+ _sep_str_grps(
272
+ [f'{self.py.root}/lib'],
273
+ # ['$ENV{HOME}/src/python/cpython'],
274
+ ),
275
+ ))
276
+
277
+ self.g.write_var(cmake.Var(
278
+ f'{self.var_prefix}_LINK_LIBRARIES',
279
+ _sep_str_grps(
280
+ *([[
281
+ '-bundle',
282
+ '"-undefined dynamic_lookup"',
283
+ ]] if sys.platform == 'darwin' else []),
284
+ ),
285
+ ))
286
+
287
+ for ext_src in self.p.ext_files():
288
+ self._add_ext(os.path.relpath(ext_src, self.p.prj_root))
289
+
290
+ #
291
+
292
+ def run(self) -> None:
293
+ if not os.path.isfile(os.path.join(self._prj_root, 'pyproject.toml')):
294
+ raise Exception('Must be run in project root')
295
+
296
+ self.ext_files()
297
+
298
+ log.info('Generating cmake project %s', self.prj_name())
299
+
300
+ self.cmake_dir()
301
+ self.write_git_ignore()
302
+ self.write_idea_name()
303
+
304
+ out = io.StringIO()
305
+ clg = self._CmakeListsGen(self, out)
306
+ clg.run()
307
+
308
+ with open(os.path.join(self.cmake_dir(), 'CMakeLists.txt'), 'w') as f:
309
+ f.write(out.getvalue())
310
+
311
+
312
+ ##
313
+
314
+
315
+ def _gen_cmd(args) -> None:
316
+ if not args.exts:
317
+ raise Exception('must specify exts')
318
+
319
+ cpg = CmakeProjectGen(args.exts)
320
+ cpg.run()
321
+
322
+
323
+ def _main(argv=None) -> None:
324
+ logs.configure_standard_logging('INFO')
325
+
326
+ parser = argparse.ArgumentParser()
327
+
328
+ subparsers = parser.add_subparsers()
329
+
330
+ parser_gen = subparsers.add_parser('gen')
331
+ parser_gen.add_argument('exts', nargs='*')
332
+ parser_gen.set_defaults(func=_gen_cmd)
333
+
334
+ args = parser.parse_args(argv)
335
+ if not getattr(args, 'func', None):
336
+ parser.print_help()
337
+ else:
338
+ args.func(args)
339
+
340
+
341
+ if __name__ == '__main__':
342
+ _main()
@@ -12,7 +12,7 @@ log = logging.getLogger(__name__)
12
12
  SCAN_COMMENT = '// @omdev-ext'
13
13
 
14
14
 
15
- def _scan_one(
15
+ def scan_one(
16
16
  input_path: str,
17
17
  **kwargs: ta.Any,
18
18
  ) -> None:
@@ -42,7 +42,7 @@ def _scan_cmd(args) -> None:
42
42
  log.info('Scanning %s', i)
43
43
  for we_dirpath, we_dirnames, we_filenames in os.walk(i): # noqa
44
44
  for fname in we_filenames:
45
- _scan_one(
45
+ scan_one(
46
46
  os.path.abspath(os.path.join(we_dirpath, fname)),
47
47
  )
48
48
 
@@ -28,8 +28,11 @@ def find_magic(
28
28
  continue
29
29
 
30
30
  fp = os.path.join(dp, fn)
31
- with open(fp) as f:
32
- src = f.read()
31
+ try:
32
+ with open(fp) as f:
33
+ src = f.read()
34
+ except UnicodeDecodeError:
35
+ continue
33
36
 
34
37
  if not any(
35
38
  any(pat.fullmatch(l) for pat in pats)
@@ -29,13 +29,18 @@ import threading
29
29
  import typing as ta
30
30
 
31
31
 
32
+ # ../../versioning/versions.py
32
33
  VersionLocalType = ta.Tuple[ta.Union[int, str], ...]
33
34
  VersionCmpPrePostDevType = ta.Union['InfinityVersionType', 'NegativeInfinityVersionType', ta.Tuple[str, int]]
34
35
  _VersionCmpLocalType0 = ta.Tuple[ta.Union[ta.Tuple[int, str], ta.Tuple['NegativeInfinityVersionType', ta.Union[int, str]]], ...] # noqa
35
36
  VersionCmpLocalType = ta.Union['NegativeInfinityVersionType', _VersionCmpLocalType0]
36
37
  VersionCmpKey = ta.Tuple[int, ta.Tuple[int, ...], VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpLocalType] # noqa
37
38
  VersionComparisonMethod = ta.Callable[[VersionCmpKey, VersionCmpKey], bool]
39
+
40
+ # ../../../omlish/lite/check.py
38
41
  T = ta.TypeVar('T')
42
+
43
+ # ../../versioning/specifiers.py
39
44
  UnparsedVersion = ta.Union['Version', str]
40
45
  UnparsedVersionVar = ta.TypeVar('UnparsedVersionVar', bound=UnparsedVersion)
41
46
  CallableVersionOperator = ta.Callable[['Version', str], bool]
@@ -55,16 +55,23 @@ import uuid
55
55
  import weakref # noqa
56
56
 
57
57
 
58
+ # ../../toml/parser.py
58
59
  TomlParseFloat = ta.Callable[[str], ta.Any]
59
60
  TomlKey = ta.Tuple[str, ...]
60
61
  TomlPos = int # ta.TypeAlias
62
+
63
+ # ../../versioning/versions.py
61
64
  VersionLocalType = ta.Tuple[ta.Union[int, str], ...]
62
65
  VersionCmpPrePostDevType = ta.Union['InfinityVersionType', 'NegativeInfinityVersionType', ta.Tuple[str, int]]
63
66
  _VersionCmpLocalType0 = ta.Tuple[ta.Union[ta.Tuple[int, str], ta.Tuple['NegativeInfinityVersionType', ta.Union[int, str]]], ...] # noqa
64
67
  VersionCmpLocalType = ta.Union['NegativeInfinityVersionType', _VersionCmpLocalType0]
65
68
  VersionCmpKey = ta.Tuple[int, ta.Tuple[int, ...], VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpPrePostDevType, VersionCmpLocalType] # noqa
66
69
  VersionComparisonMethod = ta.Callable[[VersionCmpKey, VersionCmpKey], bool]
70
+
71
+ # ../../../omlish/lite/check.py
67
72
  T = ta.TypeVar('T')
73
+
74
+ # ../../versioning/specifiers.py
68
75
  UnparsedVersion = ta.Union['Version', str]
69
76
  UnparsedVersionVar = ta.TypeVar('UnparsedVersionVar', bound=UnparsedVersion)
70
77
  CallableVersionOperator = ta.Callable[['Version', str], bool]
@@ -0,0 +1,173 @@
1
+ """
2
+ TODO:
3
+ - omlish-lite, move to pyproject/
4
+ - vendor-lite wheel.wheelfile
5
+ """
6
+ # ruff: noqa: TCH003 UP006 UP007
7
+ # @omlish-lite
8
+ import argparse
9
+ import io
10
+ import os.path
11
+ import subprocess
12
+ import tarfile
13
+ import typing as ta
14
+ import zipfile
15
+
16
+ from omlish.lite.logs import configure_standard_logging
17
+ from omlish.lite.logs import log
18
+
19
+ from ..wheelfile import WheelFile
20
+
21
+
22
+ class RevisionAdder:
23
+ def __init__(
24
+ self,
25
+ revision: str,
26
+ output_suffix: ta.Optional[str] = None,
27
+ ) -> None:
28
+ super().__init__()
29
+ self._revision = revision
30
+ self._output_suffix = output_suffix
31
+
32
+ REVISION_ATTR = '__revision__'
33
+
34
+ def add_to_contents(self, dct: ta.Dict[str, bytes]) -> bool:
35
+ changed = False
36
+ for n in dct:
37
+ if not n.endswith('__about__.py'):
38
+ continue
39
+ src = dct[n].decode('utf-8')
40
+ lines = src.splitlines(keepends=True)
41
+ for i, l in enumerate(lines):
42
+ if l != f'{self.REVISION_ATTR} = None\n':
43
+ continue
44
+ lines[i] = f"{self.REVISION_ATTR} = '{self._revision}'\n"
45
+ changed = True
46
+ dct[n] = ''.join(lines).encode('utf-8')
47
+ return changed
48
+
49
+ def add_to_wheel(self, f: str) -> None:
50
+ if not f.endswith('.whl'):
51
+ raise Exception(f)
52
+ log.info('Scanning wheel %s', f)
53
+
54
+ zis: ta.Dict[str, zipfile.ZipInfo] = {}
55
+ dct: ta.Dict[str, bytes] = {}
56
+ with WheelFile(f) as wf:
57
+ for zi in wf.filelist:
58
+ if zi.filename == wf.record_path:
59
+ continue
60
+ zis[zi.filename] = zi
61
+ dct[zi.filename] = wf.read(zi.filename)
62
+
63
+ if self.add_to_contents(dct):
64
+ of = f[:-4] + (self._output_suffix or '') + '.whl'
65
+ log.info('Repacking wheel %s', of)
66
+ with WheelFile(of, 'w') as wf:
67
+ for n, d in dct.items():
68
+ log.info('Adding zipinfo %s', n)
69
+ wf.writestr(zis[n], d)
70
+
71
+ def add_to_tgz(self, f: str) -> None:
72
+ if not f.endswith('.tar.gz'):
73
+ raise Exception(f)
74
+ log.info('Scanning tgz %s', f)
75
+
76
+ tis: ta.Dict[str, tarfile.TarInfo] = {}
77
+ dct: ta.Dict[str, bytes] = {}
78
+ with tarfile.open(f, 'r:gz') as tf:
79
+ for ti in tf:
80
+ tis[ti.name] = ti
81
+ if ti.type == tarfile.REGTYPE:
82
+ with tf.extractfile(ti.name) as tif: # type: ignore
83
+ dct[ti.name] = tif.read()
84
+
85
+ if self.add_to_contents(dct):
86
+ of = f[:-7] + (self._output_suffix or '') + '.tar.gz'
87
+ log.info('Repacking tgz %s', of)
88
+ with tarfile.open(of, 'w:gz') as tf:
89
+ for n, ti in tis.items():
90
+ log.info('Adding tarinfo %s', n)
91
+ if n in dct:
92
+ data = dct[n]
93
+ ti.size = len(data)
94
+ fo = io.BytesIO(data)
95
+ else:
96
+ fo = None
97
+ tf.addfile(ti, fileobj=fo)
98
+
99
+ EXTS = ('.tar.gz', '.whl')
100
+
101
+ def add_to_file(self, f: str) -> None:
102
+ if f.endswith('.whl'):
103
+ self.add_to_wheel(f)
104
+
105
+ elif f.endswith('.tar.gz'):
106
+ self.add_to_tgz(f)
107
+
108
+ def add_to(self, tgt: str) -> None:
109
+ if os.path.isfile(tgt):
110
+ self.add_to_file(tgt)
111
+
112
+ elif os.path.isdir(tgt):
113
+ for dp, dns, fns in os.walk(tgt): # noqa
114
+ for f in fns:
115
+ if any(f.endswith(ext) for ext in self.EXTS):
116
+ self.add_to_file(os.path.join(dp, f))
117
+
118
+
119
+ #
120
+
121
+
122
+ def get_revision() -> str:
123
+ return subprocess.check_output([
124
+ 'git',
125
+ 'describe',
126
+ '--match=NeVeRmAtCh',
127
+ '--always',
128
+ '--abbrev=40',
129
+ '--dirty',
130
+ ]).decode().strip()
131
+
132
+
133
+ #
134
+
135
+
136
+ def _add_cmd(args) -> None:
137
+ if (revision := args.revision) is None:
138
+ revision = get_revision()
139
+ log.info('Using revision %s', revision)
140
+
141
+ if not args.targets:
142
+ raise Exception('must specify targets')
143
+
144
+ ra = RevisionAdder(
145
+ revision,
146
+ output_suffix=args.suffix,
147
+ )
148
+ for tgt in args.targets:
149
+ ra.add_to(tgt)
150
+
151
+
152
+ def _main(argv=None) -> None:
153
+ configure_standard_logging('INFO')
154
+
155
+ parser = argparse.ArgumentParser()
156
+
157
+ subparsers = parser.add_subparsers()
158
+
159
+ parser_add = subparsers.add_parser('add')
160
+ parser_add.add_argument('-r', '--revision')
161
+ parser_add.add_argument('-s', '--suffix')
162
+ parser_add.add_argument('targets', nargs='*')
163
+ parser_add.set_defaults(func=_add_cmd)
164
+
165
+ args = parser.parse_args(argv)
166
+ if not getattr(args, 'func', None):
167
+ parser.print_help()
168
+ else:
169
+ args.func(args)
170
+
171
+
172
+ if __name__ == '__main__':
173
+ _main()