build_config.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. # Copyright Materialize, Inc. and contributors. All rights reserved.
  2. #
  3. # Use of this software is governed by the Business Source License
  4. # included in the LICENSE file at the root of this repository.
  5. #
  6. # As of the Change Date specified in that file, in accordance with
  7. # the Business Source License, use of this software will be governed
  8. # by the Apache License, Version 2.0.
  9. import os
  10. from pathlib import Path
  11. from textwrap import dedent
  12. from typing import Any
  13. import toml
  14. class BuildConfig:
  15. """Configuration for builds of Materialize.
  16. Most things should be configured via a tool's native configuration file,
  17. e.g. `.bazelrc` or `.cargo/config.toml`. This exists for Materialize's home
  18. grown tools, or to extend tools that don't support an option we need.
  19. Looks for configuration files in `~/.config/materialize/build.toml`
  20. """
  21. def __init__(self, path: Path):
  22. if path.is_file():
  23. with open(path) as f:
  24. raw_data = toml.load(f)
  25. else:
  26. raw_data = {}
  27. self.bazel = BazelConfig(raw_data.get("bazel", {}))
  28. @staticmethod
  29. def read():
  30. home = Path.home()
  31. path = home / ".config" / "materialize" / "build.toml"
  32. return BuildConfig(path)
  33. def __str__(self):
  34. return f"{self.bazel}"
  35. class BazelConfig:
  36. """Configuration for Bazel builds.
  37. Most configuration should go into either the repositories `.bazelrc` file
  38. or documented to be included in a users' home `.bazelrc` file. This exists
  39. for flags that Bazel does not have an easy way to configure itself.
  40. [bazel]
  41. remote_cache = "localhost:6889"
  42. """
  43. def __init__(self, data: dict[str, Any]):
  44. self.remote_cache = data.get("remote_cache", None)
  45. self.remote_cache_check_interval_minutes = data.get(
  46. "remote_cache_check_interval_minutes", "5"
  47. )
  48. def __str__(self):
  49. return dedent(
  50. f"""
  51. Bazel:
  52. remote_cache = {self.remote_cache}
  53. """
  54. )
  55. class LocalState:
  56. """Local state persisted by a tool.
  57. Users should not expect this state to be durable, it can be blown away at
  58. at point.
  59. Stored at: ~/.cache/materialize/build_state.toml
  60. """
  61. def __init__(self, path: Path):
  62. self.path = path
  63. if path.is_file():
  64. with open(path) as f:
  65. self.data = toml.load(f)
  66. else:
  67. self.data = {}
  68. @staticmethod
  69. def default_path() -> Path:
  70. home = Path.home()
  71. path = home / ".cache" / "materialize" / "build_state.toml"
  72. return path
  73. @classmethod
  74. def read(cls, namespace: str) -> Any | None:
  75. cache = LocalState(LocalState.default_path())
  76. return cache.data.get(namespace, None)
  77. @classmethod
  78. def write(cls, namespace: str, val: Any):
  79. cache = LocalState(LocalState.default_path())
  80. cache.data[namespace] = val
  81. Path(os.path.dirname(cache.path)).mkdir(parents=True, exist_ok=True)
  82. with open(cache.path, "w+") as f:
  83. toml.dump(cache.data, f)
  84. class TeleportLocalState:
  85. def __init__(self, data: dict[str, Any] | None):
  86. self.data = data or {}
  87. @classmethod
  88. def read(cls):
  89. return TeleportLocalState(LocalState.read("teleport"))
  90. def write(self):
  91. LocalState.write("teleport", self.data)
  92. def get_pid(self, app_name: str) -> str | None:
  93. existing = self.data.get(app_name, {})
  94. return existing.get("pid")
  95. def set_pid(self, app_name: str, pid: str | None):
  96. existing = self.data.get(app_name, {})
  97. existing["pid"] = pid
  98. self.data[app_name] = existing
  99. def get_address(self, app_name: str) -> str | None:
  100. existing = self.data.get(app_name, {})
  101. return existing.get("address")
  102. def set_address(self, app_name: str, addr: str | None):
  103. existing = self.data.get(app_name, {})
  104. existing["address"] = addr
  105. self.data[app_name] = existing
  106. def __str__(self):
  107. return dedent(
  108. f"""
  109. TeleportLocalState:
  110. data: {self.data}
  111. """
  112. )