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

Sign up to get free protection for your applications and to get access to all the features.
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):