ominfra 0.0.0.dev147__py3-none-any.whl → 0.0.0.dev149__py3-none-any.whl

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 (36) hide show
  1. ominfra/clouds/aws/cli.py +1 -1
  2. ominfra/configs.py +30 -5
  3. ominfra/journald/messages.py +1 -1
  4. ominfra/manage/commands/base.py +5 -5
  5. ominfra/manage/commands/execution.py +2 -2
  6. ominfra/manage/commands/inject.py +1 -1
  7. ominfra/manage/commands/interp.py +2 -2
  8. ominfra/manage/commands/subprocess.py +22 -14
  9. ominfra/manage/deploy/command.py +1 -1
  10. ominfra/manage/deploy/paths.py +2 -2
  11. ominfra/manage/main.py +48 -32
  12. ominfra/manage/remote/_main.py +172 -0
  13. ominfra/manage/remote/channel.py +41 -16
  14. ominfra/manage/remote/config.py +10 -0
  15. ominfra/manage/remote/connection.py +106 -0
  16. ominfra/manage/remote/execution.py +244 -155
  17. ominfra/manage/remote/inject.py +7 -3
  18. ominfra/manage/remote/spawning.py +51 -33
  19. ominfra/pyremote.py +28 -3
  20. ominfra/scripts/journald2aws.py +195 -91
  21. ominfra/scripts/manage.py +1366 -486
  22. ominfra/scripts/supervisor.py +533 -479
  23. ominfra/supervisor/dispatchers.py +1 -1
  24. ominfra/supervisor/http.py +2 -2
  25. ominfra/supervisor/inject.py +4 -4
  26. ominfra/supervisor/io.py +1 -1
  27. ominfra/supervisor/spawningimpl.py +1 -1
  28. ominfra/supervisor/supervisor.py +1 -1
  29. ominfra/supervisor/types.py +1 -1
  30. ominfra/tailscale/cli.py +1 -1
  31. {ominfra-0.0.0.dev147.dist-info → ominfra-0.0.0.dev149.dist-info}/METADATA +3 -3
  32. {ominfra-0.0.0.dev147.dist-info → ominfra-0.0.0.dev149.dist-info}/RECORD +36 -34
  33. {ominfra-0.0.0.dev147.dist-info → ominfra-0.0.0.dev149.dist-info}/LICENSE +0 -0
  34. {ominfra-0.0.0.dev147.dist-info → ominfra-0.0.0.dev149.dist-info}/WHEEL +0 -0
  35. {ominfra-0.0.0.dev147.dist-info → ominfra-0.0.0.dev149.dist-info}/entry_points.txt +0 -0
  36. {ominfra-0.0.0.dev147.dist-info → ominfra-0.0.0.dev149.dist-info}/top_level.txt +0 -0
@@ -1431,135 +1431,7 @@ def parse_octal(arg: ta.Union[str, int]) -> int:
1431
1431
 
1432
1432
 
1433
1433
  ########################################
1434
- # ../../../omlish/lite/cached.py
1435
-
1436
-
1437
- class _cached_nullary: # noqa
1438
- def __init__(self, fn):
1439
- super().__init__()
1440
- self._fn = fn
1441
- self._value = self._missing = object()
1442
- functools.update_wrapper(self, fn)
1443
-
1444
- def __call__(self, *args, **kwargs): # noqa
1445
- if self._value is self._missing:
1446
- self._value = self._fn()
1447
- return self._value
1448
-
1449
- def __get__(self, instance, owner): # noqa
1450
- bound = instance.__dict__[self._fn.__name__] = self.__class__(self._fn.__get__(instance, owner))
1451
- return bound
1452
-
1453
-
1454
- def cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
1455
- return _cached_nullary(fn)
1456
-
1457
-
1458
- def static_init(fn: CallableT) -> CallableT:
1459
- fn = cached_nullary(fn)
1460
- fn()
1461
- return fn
1462
-
1463
-
1464
- ########################################
1465
- # ../../../omlish/lite/check.py
1466
-
1467
-
1468
- def check_isinstance(v: ta.Any, spec: ta.Union[ta.Type[T], tuple]) -> T:
1469
- if not isinstance(v, spec):
1470
- raise TypeError(v)
1471
- return v
1472
-
1473
-
1474
- def check_not_isinstance(v: T, spec: ta.Union[type, tuple]) -> T:
1475
- if isinstance(v, spec):
1476
- raise TypeError(v)
1477
- return v
1478
-
1479
-
1480
- def check_none(v: T) -> None:
1481
- if v is not None:
1482
- raise ValueError(v)
1483
-
1484
-
1485
- def check_not_none(v: ta.Optional[T]) -> T:
1486
- if v is None:
1487
- raise ValueError
1488
- return v
1489
-
1490
-
1491
- def check_not(v: ta.Any) -> None:
1492
- if v:
1493
- raise ValueError(v)
1494
- return v
1495
-
1496
-
1497
- def check_non_empty_str(v: ta.Optional[str]) -> str:
1498
- if not v:
1499
- raise ValueError
1500
- return v
1501
-
1502
-
1503
- def check_state(v: bool, msg: str = 'Illegal state') -> None:
1504
- if not v:
1505
- raise ValueError(msg)
1506
-
1507
-
1508
- def check_equal(l: T, r: T) -> T:
1509
- if l != r:
1510
- raise ValueError(l, r)
1511
- return l
1512
-
1513
-
1514
- def check_not_equal(l: T, r: T) -> T:
1515
- if l == r:
1516
- raise ValueError(l, r)
1517
- return l
1518
-
1519
-
1520
- def check_is(l: T, r: T) -> T:
1521
- if l is not r:
1522
- raise ValueError(l, r)
1523
- return l
1524
-
1525
-
1526
- def check_is_not(l: T, r: ta.Any) -> T:
1527
- if l is r:
1528
- raise ValueError(l, r)
1529
- return l
1530
-
1531
-
1532
- def check_in(v: T, c: ta.Container[T]) -> T:
1533
- if v not in c:
1534
- raise ValueError(v, c)
1535
- return v
1536
-
1537
-
1538
- def check_not_in(v: T, c: ta.Container[T]) -> T:
1539
- if v in c:
1540
- raise ValueError(v, c)
1541
- return v
1542
-
1543
-
1544
- def check_single(vs: ta.Iterable[T]) -> T:
1545
- [v] = vs
1546
- return v
1547
-
1548
-
1549
- def check_empty(v: SizedT) -> SizedT:
1550
- if len(v):
1551
- raise ValueError(v)
1552
- return v
1553
-
1554
-
1555
- def check_non_empty(v: SizedT) -> SizedT:
1556
- if not len(v):
1557
- raise ValueError(v)
1558
- return v
1559
-
1560
-
1561
- ########################################
1562
- # ../../../omlish/lite/fdio/pollers.py
1434
+ # ../../../omlish/io/fdio/pollers.py
1563
1435
 
1564
1436
 
1565
1437
  ##
@@ -1769,118 +1641,276 @@ else:
1769
1641
 
1770
1642
 
1771
1643
  ########################################
1772
- # ../../../omlish/lite/http/versions.py
1773
-
1644
+ # ../../../omlish/lite/cached.py
1774
1645
 
1775
- class HttpProtocolVersion(ta.NamedTuple):
1776
- major: int
1777
- minor: int
1778
1646
 
1779
- def __str__(self) -> str:
1780
- return f'HTTP/{self.major}.{self.minor}'
1647
+ ##
1781
1648
 
1782
1649
 
1783
- class HttpProtocolVersions:
1784
- HTTP_0_9 = HttpProtocolVersion(0, 9)
1785
- HTTP_1_0 = HttpProtocolVersion(1, 0)
1786
- HTTP_1_1 = HttpProtocolVersion(1, 1)
1787
- HTTP_2_0 = HttpProtocolVersion(2, 0)
1650
+ class _AbstractCachedNullary:
1651
+ def __init__(self, fn):
1652
+ super().__init__()
1653
+ self._fn = fn
1654
+ self._value = self._missing = object()
1655
+ functools.update_wrapper(self, fn)
1788
1656
 
1657
+ def __call__(self, *args, **kwargs): # noqa
1658
+ raise TypeError
1789
1659
 
1790
- ########################################
1791
- # ../../../omlish/lite/json.py
1660
+ def __get__(self, instance, owner): # noqa
1661
+ bound = instance.__dict__[self._fn.__name__] = self.__class__(self._fn.__get__(instance, owner))
1662
+ return bound
1792
1663
 
1793
1664
 
1794
1665
  ##
1795
1666
 
1796
1667
 
1797
- JSON_PRETTY_INDENT = 2
1668
+ class _CachedNullary(_AbstractCachedNullary):
1669
+ def __call__(self, *args, **kwargs): # noqa
1670
+ if self._value is self._missing:
1671
+ self._value = self._fn()
1672
+ return self._value
1798
1673
 
1799
- JSON_PRETTY_KWARGS: ta.Mapping[str, ta.Any] = dict(
1800
- indent=JSON_PRETTY_INDENT,
1801
- )
1802
1674
 
1803
- json_dump_pretty: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON_PRETTY_KWARGS) # type: ignore
1804
- json_dumps_pretty: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_PRETTY_KWARGS)
1675
+ def cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
1676
+ return _CachedNullary(fn)
1677
+
1678
+
1679
+ def static_init(fn: CallableT) -> CallableT:
1680
+ fn = cached_nullary(fn)
1681
+ fn()
1682
+ return fn
1805
1683
 
1806
1684
 
1807
1685
  ##
1808
1686
 
1809
1687
 
1810
- JSON_COMPACT_SEPARATORS = (',', ':')
1688
+ class _AsyncCachedNullary(_AbstractCachedNullary):
1689
+ async def __call__(self, *args, **kwargs):
1690
+ if self._value is self._missing:
1691
+ self._value = await self._fn()
1692
+ return self._value
1811
1693
 
1812
- JSON_COMPACT_KWARGS: ta.Mapping[str, ta.Any] = dict(
1813
- indent=None,
1814
- separators=JSON_COMPACT_SEPARATORS,
1815
- )
1816
1694
 
1817
- json_dump_compact: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON_COMPACT_KWARGS) # type: ignore
1818
- json_dumps_compact: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_COMPACT_KWARGS)
1695
+ def async_cached_nullary(fn): # ta.Callable[..., T]) -> ta.Callable[..., T]:
1696
+ return _AsyncCachedNullary(fn)
1819
1697
 
1820
1698
 
1821
1699
  ########################################
1822
- # ../../../omlish/lite/maybes.py
1823
-
1700
+ # ../../../omlish/lite/check.py
1824
1701
 
1825
- class Maybe(ta.Generic[T]):
1826
- @property
1827
- @abc.abstractmethod
1828
- def present(self) -> bool:
1829
- raise NotImplementedError
1830
1702
 
1831
- @abc.abstractmethod
1832
- def must(self) -> T:
1833
- raise NotImplementedError
1703
+ def check_isinstance(v: ta.Any, spec: ta.Union[ta.Type[T], tuple]) -> T:
1704
+ if not isinstance(v, spec):
1705
+ raise TypeError(v)
1706
+ return v
1834
1707
 
1835
- @classmethod
1836
- def just(cls, v: T) -> 'Maybe[T]':
1837
- return tuple.__new__(_Maybe, (v,)) # noqa
1838
1708
 
1839
- _empty: ta.ClassVar['Maybe']
1709
+ def check_not_isinstance(v: T, spec: ta.Union[type, tuple]) -> T:
1710
+ if isinstance(v, spec):
1711
+ raise TypeError(v)
1712
+ return v
1840
1713
 
1841
- @classmethod
1842
- def empty(cls) -> 'Maybe[T]':
1843
- return Maybe._empty
1844
1714
 
1715
+ def check_none(v: T) -> None:
1716
+ if v is not None:
1717
+ raise ValueError(v)
1845
1718
 
1846
- class _Maybe(Maybe[T], tuple):
1847
- __slots__ = ()
1848
1719
 
1849
- def __init_subclass__(cls, **kwargs):
1850
- raise TypeError
1720
+ def check_not_none(v: ta.Optional[T]) -> T:
1721
+ if v is None:
1722
+ raise ValueError
1723
+ return v
1851
1724
 
1852
- @property
1853
- def present(self) -> bool:
1854
- return bool(self)
1855
1725
 
1856
- def must(self) -> T:
1857
- if not self:
1858
- raise ValueError
1859
- return self[0]
1726
+ def check_not(v: ta.Any) -> None:
1727
+ if v:
1728
+ raise ValueError(v)
1729
+ return v
1860
1730
 
1861
1731
 
1862
- Maybe._empty = tuple.__new__(_Maybe, ()) # noqa
1732
+ def check_non_empty_str(v: ta.Optional[str]) -> str:
1733
+ if not v:
1734
+ raise ValueError
1735
+ return v
1863
1736
 
1864
1737
 
1865
- ########################################
1866
- # ../../../omlish/lite/reflect.py
1738
+ def check_arg(v: bool, msg: str = 'Illegal argument') -> None:
1739
+ if not v:
1740
+ raise ValueError(msg)
1867
1741
 
1868
1742
 
1869
- _GENERIC_ALIAS_TYPES = (
1870
- ta._GenericAlias, # type: ignore # noqa
1871
- *([ta._SpecialGenericAlias] if hasattr(ta, '_SpecialGenericAlias') else []), # noqa
1872
- )
1743
+ def check_state(v: bool, msg: str = 'Illegal state') -> None:
1744
+ if not v:
1745
+ raise ValueError(msg)
1873
1746
 
1874
1747
 
1875
- def is_generic_alias(obj, *, origin: ta.Any = None) -> bool:
1876
- return (
1877
- isinstance(obj, _GENERIC_ALIAS_TYPES) and
1878
- (origin is None or ta.get_origin(obj) is origin)
1879
- )
1748
+ def check_equal(l: T, r: T) -> T:
1749
+ if l != r:
1750
+ raise ValueError(l, r)
1751
+ return l
1880
1752
 
1881
1753
 
1882
- is_union_alias = functools.partial(is_generic_alias, origin=ta.Union)
1883
- is_callable_alias = functools.partial(is_generic_alias, origin=ta.Callable)
1754
+ def check_not_equal(l: T, r: T) -> T:
1755
+ if l == r:
1756
+ raise ValueError(l, r)
1757
+ return l
1758
+
1759
+
1760
+ def check_is(l: T, r: T) -> T:
1761
+ if l is not r:
1762
+ raise ValueError(l, r)
1763
+ return l
1764
+
1765
+
1766
+ def check_is_not(l: T, r: ta.Any) -> T:
1767
+ if l is r:
1768
+ raise ValueError(l, r)
1769
+ return l
1770
+
1771
+
1772
+ def check_in(v: T, c: ta.Container[T]) -> T:
1773
+ if v not in c:
1774
+ raise ValueError(v, c)
1775
+ return v
1776
+
1777
+
1778
+ def check_not_in(v: T, c: ta.Container[T]) -> T:
1779
+ if v in c:
1780
+ raise ValueError(v, c)
1781
+ return v
1782
+
1783
+
1784
+ def check_single(vs: ta.Iterable[T]) -> T:
1785
+ [v] = vs
1786
+ return v
1787
+
1788
+
1789
+ def check_empty(v: SizedT) -> SizedT:
1790
+ if len(v):
1791
+ raise ValueError(v)
1792
+ return v
1793
+
1794
+
1795
+ def check_not_empty(v: SizedT) -> SizedT:
1796
+ if not len(v):
1797
+ raise ValueError(v)
1798
+ return v
1799
+
1800
+
1801
+ ########################################
1802
+ # ../../../omlish/lite/http/versions.py
1803
+
1804
+
1805
+ class HttpProtocolVersion(ta.NamedTuple):
1806
+ major: int
1807
+ minor: int
1808
+
1809
+ def __str__(self) -> str:
1810
+ return f'HTTP/{self.major}.{self.minor}'
1811
+
1812
+
1813
+ class HttpProtocolVersions:
1814
+ HTTP_0_9 = HttpProtocolVersion(0, 9)
1815
+ HTTP_1_0 = HttpProtocolVersion(1, 0)
1816
+ HTTP_1_1 = HttpProtocolVersion(1, 1)
1817
+ HTTP_2_0 = HttpProtocolVersion(2, 0)
1818
+
1819
+
1820
+ ########################################
1821
+ # ../../../omlish/lite/json.py
1822
+
1823
+
1824
+ ##
1825
+
1826
+
1827
+ JSON_PRETTY_INDENT = 2
1828
+
1829
+ JSON_PRETTY_KWARGS: ta.Mapping[str, ta.Any] = dict(
1830
+ indent=JSON_PRETTY_INDENT,
1831
+ )
1832
+
1833
+ json_dump_pretty: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON_PRETTY_KWARGS) # type: ignore
1834
+ json_dumps_pretty: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_PRETTY_KWARGS)
1835
+
1836
+
1837
+ ##
1838
+
1839
+
1840
+ JSON_COMPACT_SEPARATORS = (',', ':')
1841
+
1842
+ JSON_COMPACT_KWARGS: ta.Mapping[str, ta.Any] = dict(
1843
+ indent=None,
1844
+ separators=JSON_COMPACT_SEPARATORS,
1845
+ )
1846
+
1847
+ json_dump_compact: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON_COMPACT_KWARGS) # type: ignore
1848
+ json_dumps_compact: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_COMPACT_KWARGS)
1849
+
1850
+
1851
+ ########################################
1852
+ # ../../../omlish/lite/maybes.py
1853
+
1854
+
1855
+ class Maybe(ta.Generic[T]):
1856
+ @property
1857
+ @abc.abstractmethod
1858
+ def present(self) -> bool:
1859
+ raise NotImplementedError
1860
+
1861
+ @abc.abstractmethod
1862
+ def must(self) -> T:
1863
+ raise NotImplementedError
1864
+
1865
+ @classmethod
1866
+ def just(cls, v: T) -> 'Maybe[T]':
1867
+ return tuple.__new__(_Maybe, (v,)) # noqa
1868
+
1869
+ _empty: ta.ClassVar['Maybe']
1870
+
1871
+ @classmethod
1872
+ def empty(cls) -> 'Maybe[T]':
1873
+ return Maybe._empty
1874
+
1875
+
1876
+ class _Maybe(Maybe[T], tuple):
1877
+ __slots__ = ()
1878
+
1879
+ def __init_subclass__(cls, **kwargs):
1880
+ raise TypeError
1881
+
1882
+ @property
1883
+ def present(self) -> bool:
1884
+ return bool(self)
1885
+
1886
+ def must(self) -> T:
1887
+ if not self:
1888
+ raise ValueError
1889
+ return self[0]
1890
+
1891
+
1892
+ Maybe._empty = tuple.__new__(_Maybe, ()) # noqa
1893
+
1894
+
1895
+ ########################################
1896
+ # ../../../omlish/lite/reflect.py
1897
+
1898
+
1899
+ _GENERIC_ALIAS_TYPES = (
1900
+ ta._GenericAlias, # type: ignore # noqa
1901
+ *([ta._SpecialGenericAlias] if hasattr(ta, '_SpecialGenericAlias') else []), # noqa
1902
+ )
1903
+
1904
+
1905
+ def is_generic_alias(obj, *, origin: ta.Any = None) -> bool:
1906
+ return (
1907
+ isinstance(obj, _GENERIC_ALIAS_TYPES) and
1908
+ (origin is None or ta.get_origin(obj) is origin)
1909
+ )
1910
+
1911
+
1912
+ is_union_alias = functools.partial(is_generic_alias, origin=ta.Union)
1913
+ is_callable_alias = functools.partial(is_generic_alias, origin=ta.Callable)
1884
1914
 
1885
1915
 
1886
1916
  def is_optional_alias(spec: ta.Any) -> bool:
@@ -2539,65 +2569,229 @@ def get_user(name: str) -> User:
2539
2569
 
2540
2570
 
2541
2571
  ########################################
2542
- # ../../../omlish/lite/contextmanagers.py
2572
+ # ../../../omlish/io/buffers.py
2543
2573
 
2544
2574
 
2545
- ##
2575
+ class DelimitingBuffer:
2576
+ """
2577
+ https://github.com/python-trio/trio/issues/796 :|
2578
+ """
2546
2579
 
2580
+ #
2547
2581
 
2548
- class ExitStacked:
2549
- _exit_stack: ta.Optional[contextlib.ExitStack] = None
2582
+ class Error(Exception):
2583
+ def __init__(self, buffer: 'DelimitingBuffer') -> None:
2584
+ super().__init__(buffer)
2585
+ self.buffer = buffer
2550
2586
 
2551
- def __enter__(self: ExitStackedT) -> ExitStackedT:
2552
- check_state(self._exit_stack is None)
2553
- es = self._exit_stack = contextlib.ExitStack()
2554
- es.__enter__()
2555
- return self
2587
+ def __repr__(self) -> str:
2588
+ return attr_repr(self, 'buffer')
2556
2589
 
2557
- def __exit__(self, exc_type, exc_val, exc_tb):
2558
- if (es := self._exit_stack) is None:
2590
+ class ClosedError(Error):
2591
+ pass
2592
+
2593
+ #
2594
+
2595
+ DEFAULT_DELIMITERS: bytes = b'\n'
2596
+
2597
+ def __init__(
2598
+ self,
2599
+ delimiters: ta.Iterable[int] = DEFAULT_DELIMITERS,
2600
+ *,
2601
+ keep_ends: bool = False,
2602
+ max_size: ta.Optional[int] = None,
2603
+ ) -> None:
2604
+ super().__init__()
2605
+
2606
+ self._delimiters = frozenset(check_isinstance(d, int) for d in delimiters)
2607
+ self._keep_ends = keep_ends
2608
+ self._max_size = max_size
2609
+
2610
+ self._buf: ta.Optional[io.BytesIO] = io.BytesIO()
2611
+
2612
+ #
2613
+
2614
+ @property
2615
+ def is_closed(self) -> bool:
2616
+ return self._buf is None
2617
+
2618
+ def tell(self) -> int:
2619
+ if (buf := self._buf) is None:
2620
+ raise self.ClosedError(self)
2621
+ return buf.tell()
2622
+
2623
+ def peek(self) -> bytes:
2624
+ if (buf := self._buf) is None:
2625
+ raise self.ClosedError(self)
2626
+ return buf.getvalue()
2627
+
2628
+ def _find_delim(self, data: ta.Union[bytes, bytearray], i: int) -> ta.Optional[int]:
2629
+ r = None # type: int | None
2630
+ for d in self._delimiters:
2631
+ if (p := data.find(d, i)) >= 0:
2632
+ if r is None or p < r:
2633
+ r = p
2634
+ return r
2635
+
2636
+ def _append_and_reset(self, chunk: bytes) -> bytes:
2637
+ buf = check_not_none(self._buf)
2638
+ if not buf.tell():
2639
+ return chunk
2640
+
2641
+ buf.write(chunk)
2642
+ ret = buf.getvalue()
2643
+ buf.seek(0)
2644
+ buf.truncate()
2645
+ return ret
2646
+
2647
+ class Incomplete(ta.NamedTuple):
2648
+ b: bytes
2649
+
2650
+ def feed(self, data: ta.Union[bytes, bytearray]) -> ta.Generator[ta.Union[bytes, Incomplete], None, None]:
2651
+ if (buf := self._buf) is None:
2652
+ raise self.ClosedError(self)
2653
+
2654
+ if not data:
2655
+ self._buf = None
2656
+
2657
+ if buf.tell():
2658
+ yield self.Incomplete(buf.getvalue())
2659
+
2660
+ return
2661
+
2662
+ l = len(data)
2663
+ i = 0
2664
+ while i < l:
2665
+ if (p := self._find_delim(data, i)) is None:
2666
+ break
2667
+
2668
+ n = p + 1
2669
+ if self._keep_ends:
2670
+ p = n
2671
+
2672
+ yield self._append_and_reset(data[i:p])
2673
+
2674
+ i = n
2675
+
2676
+ if i >= l:
2677
+ return
2678
+
2679
+ if self._max_size is None:
2680
+ buf.write(data[i:])
2681
+ return
2682
+
2683
+ while i < l:
2684
+ remaining_data_len = l - i
2685
+ remaining_buf_capacity = self._max_size - buf.tell()
2686
+
2687
+ if remaining_data_len < remaining_buf_capacity:
2688
+ buf.write(data[i:])
2689
+ return
2690
+
2691
+ p = i + remaining_buf_capacity
2692
+ yield self.Incomplete(self._append_and_reset(data[i:p]))
2693
+ i = p
2694
+
2695
+
2696
+ class ReadableListBuffer:
2697
+ def __init__(self) -> None:
2698
+ super().__init__()
2699
+ self._lst: list[bytes] = []
2700
+
2701
+ def feed(self, d: bytes) -> None:
2702
+ if d:
2703
+ self._lst.append(d)
2704
+
2705
+ def _chop(self, i: int, e: int) -> bytes:
2706
+ lst = self._lst
2707
+ d = lst[i]
2708
+
2709
+ o = b''.join([
2710
+ *lst[:i],
2711
+ d[:e],
2712
+ ])
2713
+
2714
+ self._lst = [
2715
+ *([d[e:]] if e < len(d) else []),
2716
+ *lst[i + 1:],
2717
+ ]
2718
+
2719
+ return o
2720
+
2721
+ def read(self, n: ta.Optional[int] = None) -> ta.Optional[bytes]:
2722
+ if n is None:
2723
+ o = b''.join(self._lst)
2724
+ self._lst = []
2725
+ return o
2726
+
2727
+ if not (lst := self._lst):
2559
2728
  return None
2560
- self._exit_contexts()
2561
- return es.__exit__(exc_type, exc_val, exc_tb)
2562
2729
 
2563
- def _exit_contexts(self) -> None:
2564
- pass
2730
+ c = 0
2731
+ for i, d in enumerate(lst):
2732
+ r = n - c
2733
+ if (l := len(d)) >= r:
2734
+ return self._chop(i, r)
2735
+ c += l
2565
2736
 
2566
- def _enter_context(self, cm: ta.ContextManager[T]) -> T:
2567
- es = check_not_none(self._exit_stack)
2568
- return es.enter_context(cm)
2737
+ return None
2569
2738
 
2739
+ def read_until(self, delim: bytes = b'\n') -> ta.Optional[bytes]:
2740
+ if not (lst := self._lst):
2741
+ return None
2570
2742
 
2571
- ##
2743
+ for i, d in enumerate(lst):
2744
+ if (p := d.find(delim)) >= 0:
2745
+ return self._chop(i, p + len(delim))
2572
2746
 
2747
+ return None
2573
2748
 
2574
- @contextlib.contextmanager
2575
- def defer(fn: ta.Callable) -> ta.Generator[ta.Callable, None, None]:
2576
- try:
2577
- yield fn
2578
- finally:
2579
- fn()
2580
2749
 
2750
+ class IncrementalWriteBuffer:
2751
+ def __init__(
2752
+ self,
2753
+ data: bytes,
2754
+ *,
2755
+ write_size: int = 0x10000,
2756
+ ) -> None:
2757
+ super().__init__()
2581
2758
 
2582
- @contextlib.contextmanager
2583
- def attr_setting(obj, attr, val, *, default=None): # noqa
2584
- not_set = object()
2585
- orig = getattr(obj, attr, not_set)
2586
- try:
2587
- setattr(obj, attr, val)
2588
- if orig is not not_set:
2589
- yield orig
2590
- else:
2591
- yield default
2592
- finally:
2593
- if orig is not_set:
2594
- delattr(obj, attr)
2595
- else:
2596
- setattr(obj, attr, orig)
2759
+ check_not_empty(data)
2760
+ self._len = len(data)
2761
+ self._write_size = write_size
2762
+
2763
+ self._lst = [
2764
+ data[i:i + write_size]
2765
+ for i in range(0, len(data), write_size)
2766
+ ]
2767
+ self._pos = 0
2768
+
2769
+ @property
2770
+ def rem(self) -> int:
2771
+ return self._len - self._pos
2772
+
2773
+ def write(self, fn: ta.Callable[[bytes], int]) -> int:
2774
+ lst = check_not_empty(self._lst)
2775
+
2776
+ t = 0
2777
+ for i, d in enumerate(lst): # noqa
2778
+ n = fn(check_not_empty(d))
2779
+ if not n:
2780
+ break
2781
+ t += n
2782
+
2783
+ if t:
2784
+ self._lst = [
2785
+ *([d[n:]] if n < len(d) else []),
2786
+ *lst[i + 1:],
2787
+ ]
2788
+ self._pos += t
2789
+
2790
+ return t
2597
2791
 
2598
2792
 
2599
2793
  ########################################
2600
- # ../../../omlish/lite/fdio/handlers.py
2794
+ # ../../../omlish/io/fdio/handlers.py
2601
2795
 
2602
2796
 
2603
2797
  class FdioHandler(abc.ABC):
@@ -2661,7 +2855,7 @@ class SocketFdioHandler(FdioHandler, abc.ABC):
2661
2855
 
2662
2856
 
2663
2857
  ########################################
2664
- # ../../../omlish/lite/fdio/kqueue.py
2858
+ # ../../../omlish/io/fdio/kqueue.py
2665
2859
 
2666
2860
 
2667
2861
  KqueueFdioPoller: ta.Optional[ta.Type[FdioPoller]]
@@ -2766,19 +2960,77 @@ if sys.platform == 'darwin' or sys.platform.startswith('freebsd'):
2766
2960
  else:
2767
2961
  raise
2768
2962
 
2769
- r: ta.List[int] = []
2770
- w: ta.List[int] = []
2771
- for ke in kes:
2772
- if ke.filter == select.KQ_FILTER_READ:
2773
- r.append(ke.ident)
2774
- if ke.filter == select.KQ_FILTER_WRITE:
2775
- w.append(ke.ident)
2963
+ r: ta.List[int] = []
2964
+ w: ta.List[int] = []
2965
+ for ke in kes:
2966
+ if ke.filter == select.KQ_FILTER_READ:
2967
+ r.append(ke.ident)
2968
+ if ke.filter == select.KQ_FILTER_WRITE:
2969
+ w.append(ke.ident)
2970
+
2971
+ return FdioPoller.PollResult(r, w)
2972
+
2973
+ KqueueFdioPoller = _KqueueFdioPoller
2974
+ else:
2975
+ KqueueFdioPoller = None
2976
+
2977
+
2978
+ ########################################
2979
+ # ../../../omlish/lite/contextmanagers.py
2980
+
2981
+
2982
+ ##
2983
+
2984
+
2985
+ class ExitStacked:
2986
+ _exit_stack: ta.Optional[contextlib.ExitStack] = None
2987
+
2988
+ def __enter__(self: ExitStackedT) -> ExitStackedT:
2989
+ check_state(self._exit_stack is None)
2990
+ es = self._exit_stack = contextlib.ExitStack()
2991
+ es.__enter__()
2992
+ return self
2993
+
2994
+ def __exit__(self, exc_type, exc_val, exc_tb):
2995
+ if (es := self._exit_stack) is None:
2996
+ return None
2997
+ self._exit_contexts()
2998
+ return es.__exit__(exc_type, exc_val, exc_tb)
2999
+
3000
+ def _exit_contexts(self) -> None:
3001
+ pass
3002
+
3003
+ def _enter_context(self, cm: ta.ContextManager[T]) -> T:
3004
+ es = check_not_none(self._exit_stack)
3005
+ return es.enter_context(cm)
3006
+
3007
+
3008
+ ##
3009
+
2776
3010
 
2777
- return FdioPoller.PollResult(r, w)
3011
+ @contextlib.contextmanager
3012
+ def defer(fn: ta.Callable) -> ta.Generator[ta.Callable, None, None]:
3013
+ try:
3014
+ yield fn
3015
+ finally:
3016
+ fn()
2778
3017
 
2779
- KqueueFdioPoller = _KqueueFdioPoller
2780
- else:
2781
- KqueueFdioPoller = None
3018
+
3019
+ @contextlib.contextmanager
3020
+ def attr_setting(obj, attr, val, *, default=None): # noqa
3021
+ not_set = object()
3022
+ orig = getattr(obj, attr, not_set)
3023
+ try:
3024
+ setattr(obj, attr, val)
3025
+ if orig is not not_set:
3026
+ yield orig
3027
+ else:
3028
+ yield default
3029
+ finally:
3030
+ if orig is not_set:
3031
+ delattr(obj, attr)
3032
+ else:
3033
+ setattr(obj, attr, orig)
2782
3034
 
2783
3035
 
2784
3036
  ########################################
@@ -4074,228 +4326,6 @@ class Injection:
4074
4326
  inj = Injection
4075
4327
 
4076
4328
 
4077
- ########################################
4078
- # ../../../omlish/lite/io.py
4079
-
4080
-
4081
- class DelimitingBuffer:
4082
- """
4083
- https://github.com/python-trio/trio/issues/796 :|
4084
- """
4085
-
4086
- #
4087
-
4088
- class Error(Exception):
4089
- def __init__(self, buffer: 'DelimitingBuffer') -> None:
4090
- super().__init__(buffer)
4091
- self.buffer = buffer
4092
-
4093
- def __repr__(self) -> str:
4094
- return attr_repr(self, 'buffer')
4095
-
4096
- class ClosedError(Error):
4097
- pass
4098
-
4099
- #
4100
-
4101
- DEFAULT_DELIMITERS: bytes = b'\n'
4102
-
4103
- def __init__(
4104
- self,
4105
- delimiters: ta.Iterable[int] = DEFAULT_DELIMITERS,
4106
- *,
4107
- keep_ends: bool = False,
4108
- max_size: ta.Optional[int] = None,
4109
- ) -> None:
4110
- super().__init__()
4111
-
4112
- self._delimiters = frozenset(check_isinstance(d, int) for d in delimiters)
4113
- self._keep_ends = keep_ends
4114
- self._max_size = max_size
4115
-
4116
- self._buf: ta.Optional[io.BytesIO] = io.BytesIO()
4117
-
4118
- #
4119
-
4120
- @property
4121
- def is_closed(self) -> bool:
4122
- return self._buf is None
4123
-
4124
- def tell(self) -> int:
4125
- if (buf := self._buf) is None:
4126
- raise self.ClosedError(self)
4127
- return buf.tell()
4128
-
4129
- def peek(self) -> bytes:
4130
- if (buf := self._buf) is None:
4131
- raise self.ClosedError(self)
4132
- return buf.getvalue()
4133
-
4134
- def _find_delim(self, data: ta.Union[bytes, bytearray], i: int) -> ta.Optional[int]:
4135
- r = None # type: int | None
4136
- for d in self._delimiters:
4137
- if (p := data.find(d, i)) >= 0:
4138
- if r is None or p < r:
4139
- r = p
4140
- return r
4141
-
4142
- def _append_and_reset(self, chunk: bytes) -> bytes:
4143
- buf = check_not_none(self._buf)
4144
- if not buf.tell():
4145
- return chunk
4146
-
4147
- buf.write(chunk)
4148
- ret = buf.getvalue()
4149
- buf.seek(0)
4150
- buf.truncate()
4151
- return ret
4152
-
4153
- class Incomplete(ta.NamedTuple):
4154
- b: bytes
4155
-
4156
- def feed(self, data: ta.Union[bytes, bytearray]) -> ta.Generator[ta.Union[bytes, Incomplete], None, None]:
4157
- if (buf := self._buf) is None:
4158
- raise self.ClosedError(self)
4159
-
4160
- if not data:
4161
- self._buf = None
4162
-
4163
- if buf.tell():
4164
- yield self.Incomplete(buf.getvalue())
4165
-
4166
- return
4167
-
4168
- l = len(data)
4169
- i = 0
4170
- while i < l:
4171
- if (p := self._find_delim(data, i)) is None:
4172
- break
4173
-
4174
- n = p + 1
4175
- if self._keep_ends:
4176
- p = n
4177
-
4178
- yield self._append_and_reset(data[i:p])
4179
-
4180
- i = n
4181
-
4182
- if i >= l:
4183
- return
4184
-
4185
- if self._max_size is None:
4186
- buf.write(data[i:])
4187
- return
4188
-
4189
- while i < l:
4190
- remaining_data_len = l - i
4191
- remaining_buf_capacity = self._max_size - buf.tell()
4192
-
4193
- if remaining_data_len < remaining_buf_capacity:
4194
- buf.write(data[i:])
4195
- return
4196
-
4197
- p = i + remaining_buf_capacity
4198
- yield self.Incomplete(self._append_and_reset(data[i:p]))
4199
- i = p
4200
-
4201
-
4202
- class ReadableListBuffer:
4203
- def __init__(self) -> None:
4204
- super().__init__()
4205
- self._lst: list[bytes] = []
4206
-
4207
- def feed(self, d: bytes) -> None:
4208
- if d:
4209
- self._lst.append(d)
4210
-
4211
- def _chop(self, i: int, e: int) -> bytes:
4212
- lst = self._lst
4213
- d = lst[i]
4214
-
4215
- o = b''.join([
4216
- *lst[:i],
4217
- d[:e],
4218
- ])
4219
-
4220
- self._lst = [
4221
- *([d[e:]] if e < len(d) else []),
4222
- *lst[i + 1:],
4223
- ]
4224
-
4225
- return o
4226
-
4227
- def read(self, n: ta.Optional[int] = None) -> ta.Optional[bytes]:
4228
- if n is None:
4229
- o = b''.join(self._lst)
4230
- self._lst = []
4231
- return o
4232
-
4233
- if not (lst := self._lst):
4234
- return None
4235
-
4236
- c = 0
4237
- for i, d in enumerate(lst):
4238
- r = n - c
4239
- if (l := len(d)) >= r:
4240
- return self._chop(i, r)
4241
- c += l
4242
-
4243
- return None
4244
-
4245
- def read_until(self, delim: bytes = b'\n') -> ta.Optional[bytes]:
4246
- if not (lst := self._lst):
4247
- return None
4248
-
4249
- for i, d in enumerate(lst):
4250
- if (p := d.find(delim)) >= 0:
4251
- return self._chop(i, p + len(delim))
4252
-
4253
- return None
4254
-
4255
-
4256
- class IncrementalWriteBuffer:
4257
- def __init__(
4258
- self,
4259
- data: bytes,
4260
- *,
4261
- write_size: int = 0x10000,
4262
- ) -> None:
4263
- super().__init__()
4264
-
4265
- check_non_empty(data)
4266
- self._len = len(data)
4267
- self._write_size = write_size
4268
-
4269
- self._lst = [
4270
- data[i:i + write_size]
4271
- for i in range(0, len(data), write_size)
4272
- ]
4273
- self._pos = 0
4274
-
4275
- @property
4276
- def rem(self) -> int:
4277
- return self._len - self._pos
4278
-
4279
- def write(self, fn: ta.Callable[[bytes], int]) -> int:
4280
- lst = check_non_empty(self._lst)
4281
-
4282
- t = 0
4283
- for i, d in enumerate(lst): # noqa
4284
- n = fn(check_non_empty(d))
4285
- if not n:
4286
- break
4287
- t += n
4288
-
4289
- if t:
4290
- self._lst = [
4291
- *([d[n:]] if n < len(d) else []),
4292
- *lst[i + 1:],
4293
- ]
4294
- self._pos += t
4295
-
4296
- return t
4297
-
4298
-
4299
4329
  ########################################
4300
4330
  # ../../../omlish/lite/journald.py
4301
4331
 
@@ -5183,6 +5213,33 @@ def check_runtime_version() -> None:
5183
5213
  # ../../configs.py
5184
5214
 
5185
5215
 
5216
+ def parse_config_file(
5217
+ name: str,
5218
+ f: ta.TextIO,
5219
+ ) -> ConfigMapping:
5220
+ if name.endswith('.toml'):
5221
+ return toml_loads(f.read())
5222
+
5223
+ elif any(name.endswith(e) for e in ('.yml', '.yaml')):
5224
+ yaml = __import__('yaml')
5225
+ return yaml.safe_load(f)
5226
+
5227
+ elif name.endswith('.ini'):
5228
+ import configparser
5229
+ cp = configparser.ConfigParser()
5230
+ cp.read_file(f)
5231
+ config_dct: ta.Dict[str, ta.Any] = {}
5232
+ for sec in cp.sections():
5233
+ cd = config_dct
5234
+ for k in sec.split('.'):
5235
+ cd = cd.setdefault(k, {})
5236
+ cd.update(cp.items(sec))
5237
+ return config_dct
5238
+
5239
+ else:
5240
+ return json.loads(f.read())
5241
+
5242
+
5186
5243
  def read_config_file(
5187
5244
  path: str,
5188
5245
  cls: ta.Type[T],
@@ -5190,13 +5247,10 @@ def read_config_file(
5190
5247
  prepare: ta.Optional[ta.Callable[[ConfigMapping], ConfigMapping]] = None,
5191
5248
  ) -> T:
5192
5249
  with open(path) as cf:
5193
- if path.endswith('.toml'):
5194
- config_dct = toml_loads(cf.read())
5195
- else:
5196
- config_dct = json.loads(cf.read())
5250
+ config_dct = parse_config_file(os.path.basename(path), cf)
5197
5251
 
5198
5252
  if prepare is not None:
5199
- config_dct = prepare(config_dct) # type: ignore
5253
+ config_dct = prepare(config_dct)
5200
5254
 
5201
5255
  return unmarshal_obj(config_dct, cls)
5202
5256
 
@@ -6272,7 +6326,7 @@ class ProcessGroup(
6272
6326
 
6273
6327
 
6274
6328
  ########################################
6275
- # ../../../omlish/lite/fdio/corohttp.py
6329
+ # ../../../omlish/io/fdio/corohttp.py
6276
6330
 
6277
6331
 
6278
6332
  class CoroHttpServerConnectionFdioHandler(SocketFdioHandler):