No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

gen-catalog-json.py 31KB

hace 4 años
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. import argparse
  2. import os
  3. import json
  4. import json5
  5. import itertools
  6. import base64
  7. from urllib import request, parse as url_parse
  8. from typing import NamedTuple, Tuple, List, Sequence, Union, Optional, Mapping, Iterable
  9. import re
  10. from pathlib import Path
  11. import sys
  12. import textwrap
  13. from concurrent.futures import ThreadPoolExecutor
  14. class CopyMoveTransform(NamedTuple):
  15. frm: str
  16. to: str
  17. strip_components: int = 0
  18. include: Sequence[str] = []
  19. exclude: Sequence[str] = []
  20. def to_dict(self):
  21. return {
  22. 'from': self.frm,
  23. 'to': self.to,
  24. 'include': self.include,
  25. 'exclude': self.exclude,
  26. 'strip-components': self.strip_components,
  27. }
  28. class OneEdit(NamedTuple):
  29. kind: str
  30. line: int
  31. content: Optional[str] = None
  32. def to_dict(self):
  33. d = {
  34. 'kind': self.kind,
  35. 'line': self.line,
  36. }
  37. if self.content:
  38. d['content'] = self.content
  39. return d
  40. class EditTransform(NamedTuple):
  41. path: str
  42. edits: Sequence[OneEdit] = []
  43. def to_dict(self):
  44. return {
  45. 'path': self.path,
  46. 'edits': [e.to_dict() for e in self.edits],
  47. }
  48. class WriteTransform(NamedTuple):
  49. path: str
  50. content: str
  51. def to_dict(self):
  52. return {
  53. 'path': self.path,
  54. 'content': self.content,
  55. }
  56. class RemoveTransform(NamedTuple):
  57. path: str
  58. only_matching: Sequence[str] = ()
  59. def to_dict(self):
  60. return {
  61. 'path': self.path,
  62. 'only-matching': self.only_matching,
  63. }
  64. class FSTransform(NamedTuple):
  65. copy: Optional[CopyMoveTransform] = None
  66. move: Optional[CopyMoveTransform] = None
  67. remove: Optional[RemoveTransform] = None
  68. write: Optional[WriteTransform] = None
  69. edit: Optional[EditTransform] = None
  70. def to_dict(self):
  71. d = {}
  72. if self.copy:
  73. d['copy'] = self.copy.to_dict()
  74. if self.move:
  75. d['move'] = self.move.to_dict()
  76. if self.remove:
  77. d['remove'] = self.remove.to_dict()
  78. if self.write:
  79. d['write'] = self.write.to_dict()
  80. if self.edit:
  81. d['edit'] = self.edit.to_dict()
  82. return d
  83. class Git(NamedTuple):
  84. url: str
  85. ref: str
  86. auto_lib: Optional[str] = None
  87. transforms: Sequence[FSTransform] = []
  88. def to_dict(self) -> dict:
  89. d = {
  90. 'url': self.url,
  91. 'ref': self.ref,
  92. 'transform': [f.to_dict() for f in self.transforms],
  93. }
  94. if self.auto_lib:
  95. d['auto-lib'] = self.auto_lib
  96. return d
  97. RemoteInfo = Union[Git]
  98. class Version(NamedTuple):
  99. version: str
  100. remote: RemoteInfo
  101. depends: Sequence[str] = []
  102. description: str = '(No description provided)'
  103. def to_dict(self) -> dict:
  104. ret: dict = {
  105. 'description': self.description,
  106. 'depends': list(self.depends),
  107. }
  108. if isinstance(self.remote, Git):
  109. ret['git'] = self.remote.to_dict()
  110. return ret
  111. class VersionSet(NamedTuple):
  112. version: str
  113. depends: Sequence[str]
  114. class Package(NamedTuple):
  115. name: str
  116. versions: List[Version]
  117. HTTP_POOL = ThreadPoolExecutor(10)
  118. def github_http_get(url: str):
  119. url_dat = url_parse.urlparse(url)
  120. req = request.Request(url)
  121. req.add_header('Accept-Encoding', 'application/json')
  122. req.add_header('Authorization', f'token {os.environ["GITHUB_API_TOKEN"]}')
  123. if url_dat.hostname != 'api.github.com':
  124. raise RuntimeError(f'Request is outside of api.github.com [{url}]')
  125. resp = request.urlopen(req)
  126. if resp.status != 200:
  127. raise RuntimeError(
  128. f'Request to [{url}] failed [{resp.status} {resp.reason}]')
  129. return json5.loads(resp.read())
  130. def _get_github_tree_file_content(url: str) -> bytes:
  131. json_body = github_http_get(url)
  132. content_b64 = json_body['content'].encode()
  133. assert json_body['encoding'] == 'base64', json_body
  134. content = base64.decodebytes(content_b64)
  135. return content
  136. def _version_for_github_tag(pkg_name: str, desc: str, clone_url: str,
  137. tag) -> Version:
  138. print(f'Loading tag {tag["name"]}')
  139. commit = github_http_get(tag['commit']['url'])
  140. tree = github_http_get(commit['commit']['tree']['url'])
  141. tree_content = {t['path']: t for t in tree['tree']}
  142. cands = ['package.json', 'package.jsonc', 'package.json5']
  143. for cand in cands:
  144. if cand in tree_content:
  145. package_json_fname = cand
  146. break
  147. else:
  148. raise RuntimeError(
  149. f'No package JSON5 file in tag {tag["name"]} for {pkg_name} (One of {tree_content.keys()})'
  150. )
  151. package_json = json5.loads(
  152. _get_github_tree_file_content(tree_content[package_json_fname]['url']))
  153. version = package_json['version']
  154. if pkg_name != package_json['name']:
  155. raise RuntimeError(f'package name in repo "{package_json["name"]}" '
  156. f'does not match expected name "{pkg_name}"')
  157. depends = package_json.get('depends')
  158. pairs: Iterable[str]
  159. if isinstance(depends, dict):
  160. pairs = ((k + v) for k, v in depends.items())
  161. elif isinstance(depends, list):
  162. pairs = depends
  163. elif depends is None:
  164. pairs = []
  165. else:
  166. raise RuntimeError(
  167. f'Unknown "depends" object from json file: {depends!r}')
  168. remote = Git(url=clone_url, ref=tag['name'])
  169. return Version(
  170. version, description=desc, depends=list(pairs), remote=remote)
  171. def github_package(name: str, repo: str, want_tags: Iterable[str]) -> Package:
  172. print(f'Downloading repo from {repo}')
  173. repo_data = github_http_get(f'https://api.github.com/repos/{repo}')
  174. desc = repo_data['description']
  175. avail_tags = github_http_get(repo_data['tags_url'])
  176. missing_tags = set(want_tags) - set(t['name'] for t in avail_tags)
  177. if missing_tags:
  178. raise RuntimeError(
  179. 'One or more wanted tags do not exist in '
  180. f'the repository "{repo}" (Missing: {missing_tags})')
  181. tag_items = (t for t in avail_tags if t['name'] in want_tags)
  182. versions = HTTP_POOL.map(
  183. lambda tag: _version_for_github_tag(name, desc, repo_data['clone_url'], tag),
  184. tag_items)
  185. return Package(name, list(versions))
  186. def simple_packages(name: str,
  187. description: str,
  188. git_url: str,
  189. versions: Sequence[VersionSet],
  190. auto_lib: Optional[str] = None,
  191. *,
  192. tag_fmt: str = '{}') -> Package:
  193. return Package(name, [
  194. Version(
  195. ver.version,
  196. description=description,
  197. remote=Git(
  198. git_url, tag_fmt.format(ver.version), auto_lib=auto_lib),
  199. depends=ver.depends) for ver in versions
  200. ])
  201. def many_versions(name: str,
  202. versions: Sequence[str],
  203. *,
  204. tag_fmt: str = '{}',
  205. git_url: str,
  206. auto_lib: str = None,
  207. transforms: Sequence[FSTransform] = (),
  208. description='(No description was provided)') -> Package:
  209. return Package(name, [
  210. Version(
  211. ver,
  212. description='\n'.join(textwrap.wrap(description)),
  213. remote=Git(
  214. url=git_url,
  215. ref=tag_fmt.format(ver),
  216. auto_lib=auto_lib,
  217. transforms=transforms)) for ver in versions
  218. ])
  219. # yapf: disable
  220. PACKAGES = [
  221. github_package('neo-sqlite3', 'vector-of-bool/neo-sqlite3', ['0.2.3', '0.3.0']),
  222. github_package('neo-fun', 'vector-of-bool/neo-fun', ['0.1.1', '0.2.0', '0.2.1', '0.3.0', '0.3.1', '0.3.2', '0.4.0']),
  223. github_package('neo-concepts', 'vector-of-bool/neo-concepts', (
  224. '0.2.2',
  225. '0.3.0',
  226. '0.3.1',
  227. '0.3.2',
  228. )),
  229. github_package('semver', 'vector-of-bool/semver', ['0.2.2']),
  230. github_package('pubgrub', 'vector-of-bool/pubgrub', ['0.2.1']),
  231. github_package('vob-json5', 'vector-of-bool/json5', ['0.1.5']),
  232. github_package('vob-semester', 'vector-of-bool/semester', ['0.1.0', '0.1.1', '0.2.0', '0.2.1']),
  233. many_versions(
  234. 'magic_enum',
  235. (
  236. '0.5.0',
  237. '0.6.0',
  238. '0.6.1',
  239. '0.6.2',
  240. '0.6.3',
  241. '0.6.4',
  242. '0.6.5',
  243. '0.6.6',
  244. ),
  245. description='Static reflection for enums',
  246. tag_fmt='v{}',
  247. git_url='https://github.com/Neargye/magic_enum.git',
  248. auto_lib='neargye/magic_enum',
  249. ),
  250. many_versions(
  251. 'nameof',
  252. [
  253. '0.8.3',
  254. '0.9.0',
  255. '0.9.1',
  256. '0.9.2',
  257. '0.9.3',
  258. '0.9.4',
  259. ],
  260. description='Nameof operator for modern C++',
  261. tag_fmt='v{}',
  262. git_url='https://github.com/Neargye/nameof.git',
  263. auto_lib='neargye/nameof',
  264. ),
  265. many_versions(
  266. 'range-v3',
  267. (
  268. '0.5.0',
  269. '0.9.0',
  270. '0.9.1',
  271. '0.10.0',
  272. '0.11.0',
  273. ),
  274. git_url='https://github.com/ericniebler/range-v3.git',
  275. auto_lib='range-v3/range-v3',
  276. description=
  277. 'Range library for C++14/17/20, basis for C++20\'s std::ranges',
  278. ),
  279. many_versions(
  280. 'nlohmann-json',
  281. (
  282. # '3.0.0',
  283. # '3.0.1',
  284. # '3.1.0',
  285. # '3.1.1',
  286. # '3.1.2',
  287. # '3.2.0',
  288. # '3.3.0',
  289. # '3.4.0',
  290. # '3.5.0',
  291. # '3.6.0',
  292. # '3.6.1',
  293. # '3.7.0',
  294. '3.7.1', # Only this version has the dds forked branch
  295. # '3.7.2',
  296. # '3.7.3',
  297. ),
  298. git_url='https://github.com/vector-of-bool/json.git',
  299. tag_fmt='dds/{}',
  300. description='JSON for Modern C++',
  301. ),
  302. Package('ms-wil', [
  303. Version(
  304. '2020.03.16',
  305. description='The Windows Implementation Library',
  306. remote=Git('https://github.com/vector-of-bool/wil.git',
  307. 'dds/2020.03.16'))
  308. ]),
  309. many_versions(
  310. 'ctre',
  311. (
  312. '2.8.1',
  313. '2.8.2',
  314. '2.8.3',
  315. '2.8.4',
  316. ),
  317. git_url=
  318. 'https://github.com/hanickadot/compile-time-regular-expressions.git',
  319. tag_fmt='v{}',
  320. auto_lib='hanickadot/ctre',
  321. description=
  322. 'A compile-time PCRE (almost) compatible regular expression matcher',
  323. ),
  324. Package(
  325. 'spdlog',
  326. [
  327. Version(
  328. ver,
  329. description='Fast C++ logging library',
  330. depends=['fmt+6.0.0'],
  331. remote=Git(
  332. url='https://github.com/gabime/spdlog.git',
  333. ref=f'v{ver}',
  334. transforms=[
  335. FSTransform(
  336. write=WriteTransform(
  337. path='package.json',
  338. content=json.dumps({
  339. 'name': 'spdlog',
  340. 'namespace': 'spdlog',
  341. 'version': ver,
  342. 'depends': ['fmt+6.0.0'],
  343. }))),
  344. FSTransform(
  345. write=WriteTransform(
  346. path='library.json',
  347. content=json.dumps({
  348. 'name': 'spdlog',
  349. 'uses': ['fmt/fmt']
  350. }))),
  351. FSTransform(
  352. # It's all just template instantiations.
  353. remove=RemoveTransform(path='src/'),
  354. # Tell spdlog to use the external fmt library
  355. edit=EditTransform(
  356. path='include/spdlog/tweakme.h',
  357. edits=[
  358. OneEdit(
  359. kind='insert',
  360. content='#define SPDLOG_FMT_EXTERNAL 1',
  361. line=13,
  362. ),
  363. ])),
  364. ],
  365. ),
  366. ) for ver in (
  367. '1.4.0',
  368. '1.4.1',
  369. '1.4.2',
  370. '1.5.0',
  371. '1.6.0',
  372. '1.6.1',
  373. '1.7.0',
  374. )
  375. ]),
  376. many_versions(
  377. 'fmt',
  378. (
  379. '6.0.0',
  380. '6.1.0',
  381. '6.1.1',
  382. '6.1.2',
  383. '6.2.0',
  384. '6.2.1',
  385. '7.0.0',
  386. '7.0.1',
  387. ),
  388. git_url='https://github.com/fmtlib/fmt.git',
  389. auto_lib='fmt/fmt',
  390. description='A modern formatting library : https://fmt.dev/',
  391. ),
  392. Package('catch2', [
  393. Version(
  394. '2.12.4',
  395. description='A modern C++ unit testing library',
  396. remote=Git(
  397. 'https://github.com/catchorg/Catch2.git',
  398. 'v2.12.4',
  399. auto_lib='catch2/catch2',
  400. transforms=[
  401. FSTransform(
  402. move=CopyMoveTransform(
  403. frm='include', to='include/catch2')),
  404. FSTransform(
  405. copy=CopyMoveTransform(frm='include', to='src'),
  406. write=WriteTransform(
  407. path='include/catch2/catch_with_main.hpp',
  408. content='''
  409. #pragma once
  410. #define CATCH_CONFIG_MAIN
  411. #include "./catch.hpp"
  412. namespace Catch {
  413. CATCH_REGISTER_REPORTER("console", ConsoleReporter)
  414. }
  415. ''')),
  416. ]))
  417. ]),
  418. Package('asio', [
  419. Version(
  420. ver,
  421. description='Asio asynchronous I/O C++ library',
  422. remote=Git(
  423. 'https://github.com/chriskohlhoff/asio.git',
  424. f'asio-{ver.replace(".", "-")}',
  425. auto_lib='asio/asio',
  426. transforms=[
  427. FSTransform(
  428. move=CopyMoveTransform(
  429. frm='asio/src',
  430. to='src/',
  431. ),
  432. remove=RemoveTransform(
  433. path='src/',
  434. only_matching=[
  435. 'doc/**',
  436. 'examples/**',
  437. 'tests/**',
  438. 'tools/**',
  439. ],
  440. ),
  441. ),
  442. FSTransform(
  443. move=CopyMoveTransform(
  444. frm='asio/include/',
  445. to='include/',
  446. ),
  447. edit=EditTransform(
  448. path='include/asio/detail/config.hpp',
  449. edits=[
  450. OneEdit(
  451. line=13,
  452. kind='insert',
  453. content='#define ASIO_STANDALONE 1'),
  454. OneEdit(
  455. line=14,
  456. kind='insert',
  457. content=
  458. '#define ASIO_SEPARATE_COMPILATION 1')
  459. ]),
  460. ),
  461. ]),
  462. ) for ver in [
  463. '1.12.0',
  464. '1.12.1',
  465. '1.12.2',
  466. '1.13.0',
  467. '1.14.0',
  468. '1.14.1',
  469. '1.16.0',
  470. '1.16.1',
  471. ]
  472. ]),
  473. Package(
  474. 'abseil',
  475. [
  476. Version(
  477. ver,
  478. description='Abseil Common Libraries',
  479. remote=Git(
  480. 'https://github.com/abseil/abseil-cpp.git',
  481. tag,
  482. auto_lib='abseil/abseil',
  483. transforms=[
  484. FSTransform(
  485. move=CopyMoveTransform(
  486. frm='absl',
  487. to='src/absl/',
  488. ),
  489. remove=RemoveTransform(
  490. path='src/',
  491. only_matching=[
  492. '**/*_test.c*',
  493. '**/*_testing.c*',
  494. '**/*_benchmark.c*',
  495. '**/benchmarks.c*',
  496. '**/*_test_common.c*',
  497. '**/mocking_*.c*',
  498. # Misc files that should be removed:
  499. '**/test_util.cc',
  500. '**/mutex_nonprod.cc',
  501. '**/named_generator.cc',
  502. '**/print_hash_of.cc',
  503. '**/*_gentables.cc',
  504. ]),
  505. )
  506. ]),
  507. ) for ver, tag in [
  508. ('2018.6.0', '20180600'),
  509. ('2019.8.8', '20190808'),
  510. ('2020.2.25', '20200225.2'),
  511. ]
  512. ]),
  513. Package(
  514. 'zlib',
  515. [
  516. Version(
  517. ver,
  518. description=
  519. 'A massively spiffy yet delicately unobtrusive compression library',
  520. remote=Git(
  521. 'https://github.com/madler/zlib.git',
  522. tag or f'v{ver}',
  523. auto_lib='zlib/zlib',
  524. transforms=[
  525. FSTransform(
  526. move=CopyMoveTransform(
  527. frm='.',
  528. to='src/',
  529. include=[
  530. '*.c',
  531. '*.h',
  532. ],
  533. )),
  534. FSTransform(
  535. move=CopyMoveTransform(
  536. frm='src/',
  537. to='include/',
  538. include=['zlib.h', 'zconf.h'],
  539. )),
  540. ]),
  541. ) for ver, tag in [
  542. ('1.2.11', None),
  543. ('1.2.10', None),
  544. ('1.2.9', None),
  545. ('1.2.8', None),
  546. ('1.2.7', 'v1.2.7.3'),
  547. ('1.2.6', 'v1.2.6.1'),
  548. ('1.2.5', 'v1.2.5.3'),
  549. ('1.2.4', 'v1.2.4.5'),
  550. ('1.2.3', 'v1.2.3.8'),
  551. ('1.2.2', 'v1.2.2.4'),
  552. ('1.2.1', 'v1.2.1.2'),
  553. ('1.2.0', 'v1.2.0.8'),
  554. ('1.1.4', None),
  555. ('1.1.3', None),
  556. ('1.1.2', None),
  557. ('1.1.1', None),
  558. ('1.1.0', None),
  559. ('1.0.9', None),
  560. ('1.0.8', None),
  561. ('1.0.7', None),
  562. # ('1.0.6', None), # Does not exist
  563. ('1.0.5', None),
  564. ('1.0.4', None),
  565. # ('1.0.3', None), # Does not exist
  566. ('1.0.2', None),
  567. ('1.0.1', None),
  568. ]
  569. ]),
  570. Package('sol2', [
  571. Version(
  572. ver,
  573. description=
  574. 'A C++ <-> Lua API wrapper with advanced features and top notch performance',
  575. depends=['lua+0.0.0'],
  576. remote=Git(
  577. 'https://github.com/ThePhD/sol2.git',
  578. f'v{ver}',
  579. transforms=[
  580. FSTransform(
  581. write=WriteTransform(
  582. path='package.json',
  583. content=json.dumps(
  584. {
  585. 'name': 'sol2',
  586. 'namespace': 'sol2',
  587. 'version': ver,
  588. 'depends': [f'lua+0.0.0'],
  589. },
  590. indent=2,
  591. )),
  592. move=(None
  593. if ver.startswith('3.') else CopyMoveTransform(
  594. frm='sol',
  595. to='src/sol',
  596. )),
  597. ),
  598. FSTransform(
  599. write=WriteTransform(
  600. path='library.json',
  601. content=json.dumps(
  602. {
  603. 'name': 'sol2',
  604. 'uses': ['lua/lua'],
  605. },
  606. indent=2,
  607. ))),
  608. ]),
  609. ) for ver in [
  610. '3.2.1',
  611. '3.2.0',
  612. '3.0.3',
  613. '3.0.2',
  614. '2.20.6',
  615. '2.20.5',
  616. '2.20.4',
  617. '2.20.3',
  618. '2.20.2',
  619. '2.20.1',
  620. '2.20.0',
  621. ]
  622. ]),
  623. Package('lua', [
  624. Version(
  625. ver,
  626. description=
  627. 'Lua is a powerful and fast programming language that is easy to learn and use and to embed into your application.',
  628. remote=Git(
  629. 'https://github.com/lua/lua.git',
  630. f'v{ver}',
  631. auto_lib='lua/lua',
  632. transforms=[
  633. FSTransform(
  634. move=CopyMoveTransform(
  635. frm='.',
  636. to='src/',
  637. include=['*.c', '*.h'],
  638. ))
  639. ]),
  640. ) for ver in [
  641. '5.4.0',
  642. '5.3.5',
  643. '5.3.4',
  644. '5.3.3',
  645. '5.3.2',
  646. '5.3.1',
  647. '5.3.0',
  648. '5.2.3',
  649. '5.2.2',
  650. '5.2.1',
  651. '5.2.0',
  652. '5.1.1',
  653. ]
  654. ]),
  655. Package('pegtl', [
  656. Version(
  657. ver,
  658. description='Parsing Expression Grammar Template Library',
  659. remote=Git(
  660. 'https://github.com/taocpp/PEGTL.git',
  661. ver,
  662. auto_lib='tao/pegtl',
  663. transforms=[FSTransform(remove=RemoveTransform(path='src/'))],
  664. )) for ver in [
  665. '2.8.3',
  666. '2.8.2',
  667. '2.8.1',
  668. '2.8.0',
  669. '2.7.1',
  670. '2.7.0',
  671. '2.6.1',
  672. '2.6.0',
  673. ]
  674. ]),
  675. many_versions(
  676. 'boost.pfr', ['1.0.0', '1.0.1'],
  677. auto_lib='boost/pfr',
  678. git_url='https://github.com/apolukhin/magic_get.git'),
  679. many_versions(
  680. 'boost.leaf',
  681. [
  682. '0.1.0',
  683. '0.2.0',
  684. '0.2.1',
  685. '0.2.2',
  686. '0.2.3',
  687. '0.2.4',
  688. '0.2.5',
  689. '0.3.0',
  690. ],
  691. auto_lib='boost/leaf',
  692. git_url='https://github.com/zajo/leaf.git',
  693. ),
  694. many_versions(
  695. 'boost.mp11',
  696. ['1.70.0', '1.71.0', '1.72.0', '1.73.0'],
  697. tag_fmt='boost-{}',
  698. git_url='https://github.com/boostorg/mp11.git',
  699. auto_lib='boost/mp11',
  700. ),
  701. many_versions(
  702. 'libsodium', [
  703. '1.0.10',
  704. '1.0.11',
  705. '1.0.12',
  706. '1.0.13',
  707. '1.0.14',
  708. '1.0.15',
  709. '1.0.16',
  710. '1.0.17',
  711. '1.0.18',
  712. ],
  713. git_url='https://github.com/jedisct1/libsodium.git',
  714. auto_lib='sodium/sodium',
  715. description='Sodium is a new, easy-to-use software library '
  716. 'for encryption, decryption, signatures, password hashing and more.',
  717. transforms=[
  718. FSTransform(
  719. move=CopyMoveTransform(
  720. frm='src/libsodium/include', to='include/'),
  721. edit=EditTransform(
  722. path='include/sodium/export.h',
  723. edits=[
  724. OneEdit(
  725. line=8,
  726. kind='insert',
  727. content='#define SODIUM_STATIC 1')
  728. ])),
  729. FSTransform(
  730. edit=EditTransform(
  731. path='include/sodium/private/common.h',
  732. edits=[
  733. OneEdit(
  734. kind='insert',
  735. line=1,
  736. content=Path(__file__).parent.joinpath(
  737. 'libsodium-config.h').read_text(),
  738. )
  739. ])),
  740. FSTransform(
  741. copy=CopyMoveTransform(
  742. frm='builds/msvc/version.h',
  743. to='include/sodium/version.h',
  744. ),
  745. move=CopyMoveTransform(
  746. frm='src/libsodium',
  747. to='src/',
  748. ),
  749. remove=RemoveTransform(path='src/libsodium'),
  750. ),
  751. FSTransform(
  752. copy=CopyMoveTransform(
  753. frm='include', to='src/', strip_components=1)),
  754. ]),
  755. many_versions(
  756. 'tomlpp',
  757. [
  758. '1.0.0',
  759. '1.1.0',
  760. '1.2.0',
  761. '1.2.3',
  762. '1.2.4',
  763. '1.2.5',
  764. '1.3.0',
  765. # '1.3.2', # Wrong tag name in upstream
  766. '1.3.3',
  767. '2.0.0',
  768. ],
  769. tag_fmt='v{}',
  770. git_url='https://github.com/marzer/tomlplusplus.git',
  771. auto_lib='tomlpp/tomlpp',
  772. description=
  773. 'Header-only TOML config file parser and serializer for modern C++'),
  774. Package('inja', [
  775. *(Version(
  776. ver,
  777. description='A Template Engine for Modern C++',
  778. remote=Git(
  779. 'https://github.com/pantor/inja.git',
  780. f'v{ver}',
  781. auto_lib='inja/inja')) for ver in ('1.0.0', '2.0.0', '2.0.1')),
  782. *(Version(
  783. ver,
  784. description='A Template Engine for Modern C++',
  785. depends=['nlohmann-json+0.0.0'],
  786. remote=Git(
  787. 'https://github.com/pantor/inja.git',
  788. f'v{ver}',
  789. transforms=[
  790. FSTransform(
  791. write=WriteTransform(
  792. path='package.json',
  793. content=json.dumps({
  794. 'name':
  795. 'inja',
  796. 'namespace':
  797. 'inja',
  798. 'version':
  799. ver,
  800. 'depends': [
  801. 'nlohmann-json+0.0.0',
  802. ]
  803. }))),
  804. FSTransform(
  805. write=WriteTransform(
  806. path='library.json',
  807. content=json.dumps({
  808. 'name': 'inja',
  809. 'uses': ['nlohmann/json']
  810. }))),
  811. ],
  812. )) for ver in ('2.1.0', '2.2.0')),
  813. ]),
  814. many_versions(
  815. 'cereal',
  816. [
  817. '0.9.0',
  818. '0.9.1',
  819. '1.0.0',
  820. '1.1.0',
  821. '1.1.1',
  822. '1.1.2',
  823. '1.2.0',
  824. '1.2.1',
  825. '1.2.2',
  826. '1.3.0',
  827. ],
  828. auto_lib='cereal/cereal',
  829. git_url='https://github.com/USCiLab/cereal.git',
  830. tag_fmt='v{}',
  831. description='A C++11 library for serialization',
  832. ),
  833. many_versions(
  834. 'pybind11',
  835. [
  836. '2.0.0',
  837. '2.0.1',
  838. '2.1.0',
  839. '2.1.1',
  840. '2.2.0',
  841. '2.2.1',
  842. '2.2.2',
  843. '2.2.3',
  844. '2.2.4',
  845. '2.3.0',
  846. '2.4.0',
  847. '2.4.1',
  848. '2.4.2',
  849. '2.4.3',
  850. '2.5.0',
  851. ],
  852. git_url='https://github.com/pybind/pybind11.git',
  853. description='Seamless operability between C++11 and Python',
  854. auto_lib='pybind/pybind11',
  855. tag_fmt='v{}',
  856. ),
  857. Package('pcg-cpp', [
  858. Version(
  859. '0.98.1',
  860. description='PCG Randum Number Generation, C++ Edition',
  861. remote=Git(
  862. url='https://github.com/imneme/pcg-cpp.git',
  863. ref='v0.98.1',
  864. auto_lib='pcg/pcg-cpp'))
  865. ]),
  866. many_versions(
  867. 'hinnant-date',
  868. ['2.4.1', '3.0.0'],
  869. description=
  870. 'A date and time library based on the C++11/14/17 <chrono> header',
  871. auto_lib='hinnant/date',
  872. git_url='https://github.com/HowardHinnant/date.git',
  873. tag_fmt='v{}',
  874. transforms=[FSTransform(remove=RemoveTransform(path='src/'))],
  875. ),
  876. ]
  877. # yapf: enable
  878. if __name__ == "__main__":
  879. parser = argparse.ArgumentParser()
  880. args = parser.parse_args()
  881. data = {
  882. 'version': 1,
  883. 'packages': {
  884. pkg.name: {ver.version: ver.to_dict()
  885. for ver in pkg.versions}
  886. for pkg in PACKAGES
  887. }
  888. }
  889. json_str = json.dumps(data, indent=2, sort_keys=True)
  890. Path('catalog.json').write_text(json_str)
  891. cpp_template = textwrap.dedent(r'''
  892. #include <dds/catalog/package_info.hpp>
  893. #include <dds/catalog/init_catalog.hpp>
  894. #include <dds/catalog/import.hpp>
  895. /**
  896. * The following array of integers is generated and contains the JSON
  897. * encoded initial catalog. MSVC can't handle string literals over
  898. * 64k large, so we have to resort to using a regular char array:
  899. */
  900. static constexpr const char INIT_PACKAGES_CONTENT[] = {
  901. @JSON@
  902. };
  903. static constexpr int INIT_PACKAGES_STR_LEN = @JSON_LEN@;
  904. const std::vector<dds::package_info>&
  905. dds::init_catalog_packages() noexcept {
  906. using std::nullopt;
  907. static auto pkgs = dds::parse_packages_json(
  908. std::string_view(INIT_PACKAGES_CONTENT, INIT_PACKAGES_STR_LEN));
  909. return pkgs;
  910. }
  911. ''')
  912. json_small = json.dumps(data, sort_keys=True)
  913. json_small_arr = ', '.join(str(ord(c)) for c in json_small)
  914. json_small_arr = '\n'.join(textwrap.wrap(json_small_arr, width=120))
  915. json_small_arr = textwrap.indent(json_small_arr, prefix=' ' * 4)
  916. cpp_content = cpp_template.replace('@JSON@', json_small_arr).replace(
  917. '@JSON_LEN@', str(len(json_small)))
  918. Path('src/dds/catalog/init_catalog.cpp').write_text(cpp_content)