]>
Commit | Line | Data |
---|---|---|
028b2057 MT |
1 | #!/usr/bin/python3 |
2 | ||
22a89cd7 | 3 | import asyncio |
da4b4f45 | 4 | import collections |
73747ff6 | 5 | import configparser |
1af8c243 | 6 | import io |
028b2057 | 7 | import logging |
da4b4f45 | 8 | import logging.handlers |
028b2057 | 9 | import pakfire |
028b2057 MT |
10 | |
11 | from . import base | |
12 | ||
13 | # Setup logging | |
6acc7746 | 14 | log = logging.getLogger("pbs.config") |
028b2057 MT |
15 | |
16 | class PakfireConfig(base.Object): | |
cd8c247d | 17 | def init(self, distro=None, repos=None, vendor=None, contact=None, |
46124b3a | 18 | arch=None, include_source=False, mirrored=True, build=None, logger=None): |
028b2057 MT |
19 | self.distro = distro |
20 | self.repos = set() | |
21 | ||
c7c90543 MT |
22 | # Overwritten for user repositories |
23 | self.vendor = vendor | |
24 | self.contact = contact | |
25 | ||
259e43dc MT |
26 | # Reset the architecture on noarch |
27 | if arch == "noarch": | |
28 | arch = None | |
29 | ||
cd8c247d MT |
30 | # Architecture |
31 | self.arch = arch | |
32 | ||
316ffaa3 MT |
33 | # Should the configuration include the source repositories? |
34 | self.include_source = include_source | |
35 | ||
91fb1718 MT |
36 | # Should the repositories use any mirrors? |
37 | self.mirrored = mirrored | |
38 | ||
46124b3a MT |
39 | # Is this for a build? |
40 | self.build = build | |
41 | ||
da4b4f45 MT |
42 | # Log messages to here |
43 | self.logger = logger | |
44 | ||
028b2057 | 45 | # Add all repositories belonging to the distribution |
c7d2517e MT |
46 | if self.distro: |
47 | for repo in self.distro.repos: | |
48 | self.add_repo(repo) | |
028b2057 MT |
49 | |
50 | # Add any repositories | |
51 | if repos: | |
52 | for repo in repos: | |
53 | self.add_repo(repo) | |
54 | ||
55 | def __str__(self): | |
1af8c243 | 56 | config = self._make_config() |
6b441548 MT |
57 | |
58 | return self._to_string(config) | |
59 | ||
60 | def _to_string(self, config): | |
61 | buffer = io.StringIO() | |
1af8c243 MT |
62 | config.write(buffer) |
63 | ||
64 | return buffer.getvalue() | |
028b2057 | 65 | |
db548d43 MT |
66 | def _log(self, level, message): |
67 | # Remove any trailing newline (but only one) | |
68 | if message: | |
69 | message = message.removesuffix("\n") | |
70 | ||
da4b4f45 MT |
71 | # Log to the logger if configured |
72 | if self.logger: | |
73 | return self.logger(level, message) | |
74 | ||
db548d43 MT |
75 | return log.log(level, message) |
76 | ||
028b2057 MT |
77 | # Repositories |
78 | ||
79 | def add_repo(self, repo): | |
80 | """ | |
81 | Adds a repository to this configuration | |
82 | """ | |
83 | self.repos.add(repo) | |
84 | ||
85 | # Add any sibling repositories | |
dc433969 | 86 | self.repos.update(repo.parents) |
028b2057 MT |
87 | |
88 | # Context | |
89 | ||
22a89cd7 | 90 | async def __aenter__(self): |
5ca2b3bb MT |
91 | f = io.StringIO() |
92 | ||
028b2057 MT |
93 | # Make configuration |
94 | config = self._make_config(local=True) | |
95 | ||
5ca2b3bb MT |
96 | # Write the configuration to the buffer |
97 | config.write(f) | |
98 | f.seek(0) | |
028b2057 | 99 | |
5ca2b3bb | 100 | log.debug("Launching Pakfire with configuration:\n%s", f.getvalue()) |
028b2057 | 101 | |
5ca2b3bb MT |
102 | # Launch a new Pakfire instance (in a separate thread) |
103 | return await asyncio.to_thread(pakfire.Pakfire, arch=self.arch, conf=f, | |
104 | logger=self._log, offline=False) | |
22a89cd7 MT |
105 | |
106 | async def __aexit__(self, type, value, traceback): | |
028b2057 MT |
107 | pass |
108 | ||
109 | def _make_config(self, local=False): | |
110 | """ | |
111 | Generates the configuration file | |
112 | """ | |
73747ff6 MT |
113 | config = configparser.ConfigParser(interpolation=None, |
114 | default_section="general") | |
115 | ||
116 | # Apply some general settings | |
deecf10c MT |
117 | if local: |
118 | config["general"] = { | |
119 | "cache_path" : self.backend.path(".cache"), | |
120 | } | |
028b2057 MT |
121 | |
122 | # Add the distro configuration | |
c7d2517e | 123 | if self.distro: |
73747ff6 | 124 | self.distro.write_config(config, local=local, |
c7c90543 | 125 | vendor=self.vendor, contact=self.contact) |
028b2057 MT |
126 | |
127 | # Add the repository configurations | |
128 | for repo in self.repos: | |
46124b3a MT |
129 | repo.write_config(config, local=local, include_source=self.include_source, |
130 | mirrored=self.mirrored, build=self.build) | |
028b2057 | 131 | |
73747ff6 | 132 | return config |
da4b4f45 MT |
133 | |
134 | ||
135 | class PakfireLogger(object): | |
136 | """ | |
137 | This is a simple logger instance which collects all log | |
138 | messages which can in the end be exported to for example being stored in the database. | |
139 | """ | |
140 | id = 0 | |
141 | ||
142 | class QueueHandler(logging.handlers.QueueHandler): | |
143 | """ | |
144 | This calls overwrites the enqueue() method so that | |
145 | we can use an alternative queue which allows us to | |
146 | iterate over its data without removing anything. | |
147 | """ | |
148 | def enqueue(self, record): | |
149 | self.queue.append(record) | |
150 | ||
151 | def __init__(self, level=logging.DEBUG): | |
152 | # Create a new child logger | |
153 | self.log = log.getChild("logger-%s" % self.id) | |
154 | self.log.setLevel(level) | |
155 | ||
156 | # Increment the ID | |
157 | self.id += 1 | |
158 | ||
159 | # Propagate messages to the parent logger | |
160 | self.log.propagate = True | |
161 | ||
162 | # Create a new queue to buffer any messages | |
163 | self.queue = collections.deque() | |
164 | ||
165 | # Create a log formatter | |
166 | formatter = logging.Formatter( | |
167 | "%(asctime)s %(levelname)-8s %(message)s" | |
168 | ) | |
169 | ||
170 | # Create a queue handler | |
171 | handler = self.QueueHandler(self.queue) | |
172 | handler.setFormatter(formatter) | |
173 | ||
174 | # Register the queue with the logger | |
175 | self.log.addHandler(handler) | |
176 | ||
177 | def __call__(self, *args, **kwargs): | |
178 | """ | |
179 | Logs a message | |
180 | """ | |
181 | return self.log.log(*args, **kwargs) | |
182 | ||
183 | def __str__(self): | |
184 | """ | |
185 | Returns the entire log as a string | |
186 | """ | |
187 | return "\n".join((record.getMessage() for record in self.queue)) |