]> git.ipfire.org Git - pbs.git/blame - src/buildservice/config.py
jobs: Force builders to refresh repository data all the time
[pbs.git] / src / buildservice / config.py
CommitLineData
028b2057
MT
1#!/usr/bin/python3
2
22a89cd7 3import asyncio
da4b4f45 4import collections
73747ff6 5import configparser
1af8c243 6import io
028b2057 7import logging
da4b4f45 8import logging.handlers
028b2057 9import pakfire
028b2057
MT
10
11from . import base
12
13# Setup logging
6acc7746 14log = logging.getLogger("pbs.config")
028b2057
MT
15
16class 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
135class 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))