Author:
Hash:
Timestamp:
+206 -355 +/-22 browse
Kevin Schoon [me@kevinschoon.com]
731ff4d7e2d40e056362047d8619e9d81b19238d
Tue, 06 Feb 2024 22:45:43 +0000 (1.3 years ago)
1 | diff --git a/ayllu-build/src/evaluate.rs b/ayllu-build/src/evaluate.rs |
2 | index 54bb5e6..644b4d1 100644 |
3 | --- a/ayllu-build/src/evaluate.rs |
4 | +++ b/ayllu-build/src/evaluate.rs |
5 | @@ -334,10 +334,14 @@ impl Runtime { |
6 | temp_dir: self.log_dir.clone(), |
7 | tee_output: self.tee_output, |
8 | }; |
9 | - let mut ctx = Context::default(); |
10 | + |
11 | // TODO: more context |
12 | - ctx.manifest_id = manifest_id; |
13 | - ctx.workflow_id = state.current_workflow().unwrap().0; |
14 | + let ctx = Context { |
15 | + manifest_id, |
16 | + workflow_id: state.current_workflow().unwrap().0, |
17 | + ..Default::default() |
18 | + }; |
19 | + |
20 | let (stdout, stderr, exit_code) = executor.execute(step, ctx)?; |
21 | if !exit_code.success() { |
22 | warn!("step {} has failed: {:?}", step.name, exit_code); |
23 | @@ -355,13 +359,10 @@ impl Runtime { |
24 | } |
25 | } |
26 | // clean up last workflow |
27 | - match state.current_workflow() { |
28 | - Some((id, duration)) => { |
29 | - db.update_workflow_finish(id, duration).await?; |
30 | - } |
31 | - |
32 | - None => {} |
33 | + if let Some((id, duration)) = state.current_workflow() { |
34 | + db.update_workflow_finish(id, duration).await?; |
35 | } |
36 | + |
37 | db.update_manifest_finish(manifest_id, state.runtime()) |
38 | .await?; |
39 | Ok(()) |
40 | diff --git a/ayllu-build/src/rpc_server.rs b/ayllu-build/src/rpc_server.rs |
41 | index fe57e0b..10fe521 100644 |
42 | --- a/ayllu-build/src/rpc_server.rs |
43 | +++ b/ayllu-build/src/rpc_server.rs |
44 | @@ -1,11 +1,7 @@ |
45 | - |
46 | - |
47 | use anyhow::Result; |
48 | use capnp::{capability::Promise, Error as CapnpError}; |
49 | - use sysinfo::SystemExt; |
50 | |
51 | use crate::config::Builder as Config; |
52 | - // use crate::database_ext::XmppExt; |
53 | use ayllu_api::build_capnp::worker::{ |
54 | Client, ListManifestsParams, ListManifestsResults, ReadManifestParams, ReadManifestResults, |
55 | Server, SubmitParams, SubmitResults, |
56 | @@ -14,6 +10,7 @@ use ayllu_api::build_capnp::worker::{ |
57 | use ayllu_database::{Builder, Wrapper as Database}; |
58 | use ayllu_rpc::Server as RpcHelper; |
59 | |
60 | + #[allow(dead_code)] |
61 | struct ServerImpl { |
62 | db: Database, |
63 | } |
64 | diff --git a/ayllu-xmpp/src/rpc_server.rs b/ayllu-xmpp/src/rpc_server.rs |
65 | index b6fb493..122bff0 100644 |
66 | --- a/ayllu-xmpp/src/rpc_server.rs |
67 | +++ b/ayllu-xmpp/src/rpc_server.rs |
68 | @@ -9,7 +9,7 @@ use crate::database_ext::XmppExt; |
69 | use ayllu_api::xmpp_capnp::server::{ |
70 | Client, MessagesParams, MessagesResults, Server, StatsParams, StatsResults, |
71 | }; |
72 | - use ayllu_database::Wrapper as Database; |
73 | + use ayllu_database::{Wrapper as Database, Builder}; |
74 | use ayllu_rpc::Server as RpcHelper; |
75 | |
76 | struct ServerImpl { |
77 | @@ -93,7 +93,7 @@ impl Server for ServerImpl { |
78 | } |
79 | |
80 | pub async fn serve(cfg: Config) -> Result<(), Box<dyn StdError>> { |
81 | - let db = Database::new(&cfg.database.path, true, false).await?; |
82 | + let db = Builder::default().url(&cfg.database.path).build().await?; |
83 | let server = ServerImpl { db }; |
84 | let runtime = RpcHelper::<Client, ServerImpl>::new(&cfg.socket_path, server); |
85 | runtime.serve().await?; |
86 | diff --git a/ayllu-xmpp/src/xmpp_bot.rs b/ayllu-xmpp/src/xmpp_bot.rs |
87 | index 33ec620..d25206b 100644 |
88 | --- a/ayllu-xmpp/src/xmpp_bot.rs |
89 | +++ b/ayllu-xmpp/src/xmpp_bot.rs |
90 | @@ -8,12 +8,15 @@ use xmpp::{ClientBuilder, ClientFeature, ClientType, Event}; |
91 | |
92 | use crate::config::Xmpp as Config; |
93 | use crate::database_ext::XmppExt; |
94 | - use ayllu_database::Wrapper as Database; |
95 | + use ayllu_database::Builder; |
96 | |
97 | pub type Error = Box<dyn StdError>; |
98 | |
99 | pub async fn serve(config: Config) -> Result<(), Error> { |
100 | - let db = Database::new(&config.database.path, false, false).await?; |
101 | + let db = Builder::default() |
102 | + .url(&config.database.path) |
103 | + .build() |
104 | + .await?; |
105 | let jid = BareJid::new(&config.jid)?; |
106 | let mut client = ClientBuilder::new(jid, &config.password) |
107 | .set_client(ClientType::Bot, "ayllu-xmpp") |
108 | @@ -54,10 +57,7 @@ pub async fn serve(config: Config) -> Result<(), Error> { |
109 | .unwrap() |
110 | .clone(); |
111 | client |
112 | - .request_room_history( |
113 | - channel_jid.clone(), |
114 | - last_message_id.as_deref(), |
115 | - ) |
116 | + .request_room_history(channel_jid.clone(), last_message_id.as_deref()) |
117 | .await |
118 | } |
119 | } |
120 | diff --git a/crates/database/src/lib.rs b/crates/database/src/lib.rs |
121 | index f19b1a6..1c38990 100644 |
122 | --- a/crates/database/src/lib.rs |
123 | +++ b/crates/database/src/lib.rs |
124 | @@ -92,15 +92,12 @@ impl Builder { |
125 | opts = opts.locking_mode(SqliteLockingMode::Normal) |
126 | } |
127 | let pool = pool_opts.connect_with(opts).await?; |
128 | - match self.migrations { |
129 | - Some(migrations_path) => { |
130 | - log::info!("running migrations"); |
131 | - Migrator::new(Path::new(&migrations_path)) |
132 | - .await? |
133 | - .run(&pool) |
134 | - .await? |
135 | - } |
136 | - None => {} |
137 | + if let Some(migrations_path) = self.migrations { |
138 | + log::info!("running migrations"); |
139 | + Migrator::new(Path::new(&migrations_path)) |
140 | + .await? |
141 | + .run(&pool) |
142 | + .await? |
143 | } |
144 | Ok(Wrapper { pool }) |
145 | } |
146 | @@ -112,30 +109,6 @@ pub struct Wrapper { |
147 | } |
148 | |
149 | impl Wrapper { |
150 | - #[deprecated] |
151 | - pub async fn new(url: &str, read_only: bool, log_queries: bool) -> Result<Self, Error> { |
152 | - let log_level = if log_queries { |
153 | - // don't log queries when the global logger is at level INFO |
154 | - log::LevelFilter::Info |
155 | - } else { |
156 | - log::LevelFilter::Debug |
157 | - }; |
158 | - // TODO: set read-only for main web serving mode |
159 | - let mut opts = SqliteConnectOptions::new() |
160 | - .log_statements(log_level) |
161 | - .filename(url) |
162 | - .serialized(true) |
163 | - // .read_only(read_only) |
164 | - .create_if_missing(false); |
165 | - if read_only { |
166 | - opts = opts.read_only(true) |
167 | - } else { |
168 | - opts = opts.locking_mode(SqliteLockingMode::Normal) |
169 | - } |
170 | - let pool = SqlitePool::connect_with(opts).await?; |
171 | - Ok(Wrapper { pool }) |
172 | - } |
173 | - |
174 | pub async fn close(&self) -> Result<(), Error> { |
175 | self.pool.close().await; |
176 | Ok(()) |
177 | diff --git a/crates/git/src/clone.rs b/crates/git/src/clone.rs |
178 | index 69c5f43..0af2c86 100644 |
179 | --- a/crates/git/src/clone.rs |
180 | +++ b/crates/git/src/clone.rs |
181 | @@ -1,6 +1,7 @@ |
182 | use crate::error::Error; |
183 | /// clone a remote repository into the given path with the specified depth. |
184 | /// this is only used as a part of ayllu-build |
185 | + #[allow(dead_code)] |
186 | pub fn clone(_url: &str, _path: &str, _depth: Option<i64>) -> Result<(), Error> { |
187 | - Ok(()) |
188 | + todo!() |
189 | } |
190 | diff --git a/crates/git/src/wrapper.rs b/crates/git/src/wrapper.rs |
191 | index 71a2ae8..9af7620 100644 |
192 | --- a/crates/git/src/wrapper.rs |
193 | +++ b/crates/git/src/wrapper.rs |
194 | @@ -42,15 +42,6 @@ impl Wrapper { |
195 | }) |
196 | } |
197 | |
198 | - pub fn from_str(path: &str) -> Result<Self, Error> { |
199 | - let path = Path::new(path); |
200 | - let repository = Repository::open(path)?; |
201 | - Ok(Wrapper { |
202 | - path: path.to_str().unwrap().to_string(), |
203 | - repository: Box::new(repository), |
204 | - }) |
205 | - } |
206 | - |
207 | pub fn path(&self) -> String { |
208 | self.path.clone() |
209 | } |
210 | diff --git a/crates/rpc/src/lib.rs b/crates/rpc/src/lib.rs |
211 | index 15790ba..618b648 100644 |
212 | --- a/crates/rpc/src/lib.rs |
213 | +++ b/crates/rpc/src/lib.rs |
214 | @@ -22,8 +22,6 @@ pub enum Kind { |
215 | Mail, |
216 | } |
217 | |
218 | - // pub type Error = Box<dyn StdError>; |
219 | - |
220 | #[derive(Debug)] |
221 | pub enum Error { |
222 | CapnpError(CapnpError), |
223 | @@ -81,11 +79,8 @@ where |
224 | |
225 | pub async fn serve(self) -> Result<(), Error> { |
226 | let socket_path = Path::new(&self.socket_path); |
227 | - match metadata(socket_path) { |
228 | - Ok(_) => { |
229 | - remove_file(socket_path)?; |
230 | - } |
231 | - Err(_) => {} |
232 | + if metadata(socket_path).is_ok() { |
233 | + remove_file(socket_path)?; |
234 | }; |
235 | // TODO: need to support both sockets and TCP connections for build |
236 | // servers since they will cross network boundaries on QEMU, etc. |
237 | @@ -158,6 +153,7 @@ pub mod helpers { |
238 | } |
239 | |
240 | /// service for testing only |
241 | + #[allow(dead_code)] |
242 | mod hello_capnp { |
243 | include!(concat!(env!("OUT_DIR"), "/hello_capnp.rs")); |
244 | } |
245 | diff --git a/crates/scheduler/src/lib.rs b/crates/scheduler/src/lib.rs |
246 | index 2dde645..399e376 100644 |
247 | --- a/crates/scheduler/src/lib.rs |
248 | +++ b/crates/scheduler/src/lib.rs |
249 | @@ -91,24 +91,21 @@ where |
250 | spawn(move || { |
251 | let mut position = 0; |
252 | loop { |
253 | - match rx.recv_timeout(Duration::from_millis(TIMEOUT_MS)) { |
254 | - Ok(next_job) => { |
255 | - info!("sending job to worker: {}", position); |
256 | - let worker = workers.get(position).unwrap(); |
257 | - worker.send(next_job).unwrap(); |
258 | - if position + 1 == n_workers { |
259 | - position = 0; |
260 | - } else { |
261 | - position += 1; |
262 | - } |
263 | + if let Ok(next_job) = rx.recv_timeout(Duration::from_millis(TIMEOUT_MS)) { |
264 | + info!("sending job to worker: {}", position); |
265 | + let worker = workers.get(position).unwrap(); |
266 | + worker.send(next_job).unwrap(); |
267 | + if position + 1 == n_workers { |
268 | + position = 0; |
269 | + } else { |
270 | + position += 1; |
271 | } |
272 | - Err(_) => {} |
273 | } |
274 | - match rx_shutdown.recv_timeout(Duration::from_millis(TIMEOUT_MS)) { |
275 | - Ok(_) => { |
276 | - info!("scheduler is shutting down") |
277 | - } |
278 | - Err(_) => {} |
279 | + if rx_shutdown |
280 | + .recv_timeout(Duration::from_millis(TIMEOUT_MS)) |
281 | + .is_ok() |
282 | + { |
283 | + info!("scheduler is shutting down") |
284 | } |
285 | } |
286 | }); |
287 | diff --git a/src/job_server/client.rs b/src/job_server/client.rs |
288 | deleted file mode 100644 |
289 | index 64e9e4a..0000000 |
290 | --- a/src/job_server/client.rs |
291 | +++ /dev/null |
292 | @@ -1,73 +0,0 @@ |
293 | - use ayllu_api::jobs_capnp::server::Client; |
294 | - use ayllu_api::models::{Job, Kind}; |
295 | - |
296 | - |
297 | - use capnp::Error; |
298 | - use capnp_rpc::{rpc_twoparty_capnp::Side, twoparty, RpcSystem}; |
299 | - use tokio::net::UnixStream; |
300 | - use tokio_util::compat::TokioAsyncReadCompatExt; |
301 | - |
302 | - use futures::AsyncReadExt; |
303 | - |
304 | - pub struct Jobs { |
305 | - socket_path: String, |
306 | - } |
307 | - |
308 | - impl Jobs { |
309 | - pub fn new(path: &str) -> Self { |
310 | - Jobs { |
311 | - socket_path: path.to_string(), |
312 | - } |
313 | - } |
314 | - |
315 | - async fn _make_client(&self) -> Result<Client, Error> { |
316 | - let stream = UnixStream::connect(self.socket_path.as_str()).await?; |
317 | - let (reader, writer) = TokioAsyncReadCompatExt::compat(stream).split(); |
318 | - let rpc_network = Box::new(twoparty::VatNetwork::new( |
319 | - reader, |
320 | - writer, |
321 | - Side::Client, |
322 | - Default::default(), |
323 | - )); |
324 | - let mut rpc_system = RpcSystem::new(rpc_network, None); |
325 | - let jobs_client: Client = rpc_system.bootstrap(Side::Server); |
326 | - tokio::task::spawn_local(rpc_system); |
327 | - Ok(jobs_client) |
328 | - } |
329 | - |
330 | - pub async fn submit(&self, repo_path: &str, kind: Kind) -> Result<(), Error> { |
331 | - let client = self._make_client().await?; |
332 | - let mut request = client.submit_request(); |
333 | - request.get().set_repo_path(repo_path.into()); |
334 | - request.get().set_kind(kind.into()); |
335 | - request.send().promise.await?; |
336 | - Ok(()) |
337 | - } |
338 | - |
339 | - pub async fn list(&self) -> Result<Vec<Job>, Error> { |
340 | - let client = self._make_client().await?; |
341 | - let result = client.list_request().send().promise.await?; |
342 | - let jobs: Vec<Job> = result |
343 | - .get()? |
344 | - .get_jobs()? |
345 | - .iter() |
346 | - .map(|item| Job { |
347 | - id: item.get_id(), |
348 | - repo_path: String::from_utf8(item.get_repo_path().unwrap().0.to_vec()).unwrap(), |
349 | - created_at: item.get_created_at(), |
350 | - runtime: item.get_runtime(), |
351 | - kind: Kind::from(item.get_kind().unwrap()), |
352 | - commits: item.get_commits(), |
353 | - }) |
354 | - .collect(); |
355 | - Ok(jobs) |
356 | - } |
357 | - |
358 | - pub async fn purge(&self, repo_path: &str) -> Result<(), Error> { |
359 | - let client = self._make_client().await?; |
360 | - let mut request = client.purge_request(); |
361 | - request.get().set_repo_path(repo_path.into()); |
362 | - request.send().promise.await?; |
363 | - Ok(()) |
364 | - } |
365 | - } |
366 | diff --git a/src/job_server/mod.rs b/src/job_server/mod.rs |
367 | index 417f7d4..0cceca5 100644 |
368 | --- a/src/job_server/mod.rs |
369 | +++ b/src/job_server/mod.rs |
370 | @@ -1,7 +1,6 @@ |
371 | pub use commands::*; |
372 | pub use server::serve; |
373 | |
374 | - mod client; |
375 | mod commands; |
376 | mod jobs; |
377 | mod runner; |
378 | diff --git a/src/job_server/server.rs b/src/job_server/server.rs |
379 | index cfdec3b..c66afcb 100644 |
380 | --- a/src/job_server/server.rs |
381 | +++ b/src/job_server/server.rs |
382 | @@ -1,6 +1,5 @@ |
383 | use std::error::Error as StdError; |
384 | use std::sync::Arc; |
385 | - use std::sync::OnceLock; |
386 | |
387 | use capnp::{capability::Promise, Error}; |
388 | use capnp_rpc::pry; |
389 | @@ -12,10 +11,9 @@ use ayllu_api::jobs_capnp::server::{ |
390 | Client, ListParams, ListResults, PurgeParams, PurgeResults, Server, SubmitParams, SubmitResults, |
391 | }; |
392 | use ayllu_api::models::{Job, Kind}; |
393 | - use ayllu_database::Wrapper as Database; |
394 | + use ayllu_database::{Wrapper as Database, Builder}; |
395 | use ayllu_rpc::Server as CapnpServerHelper; |
396 | |
397 | - static THREAD_CONFIG: OnceLock<Config> = OnceLock::new(); |
398 | |
399 | #[derive(Clone)] |
400 | pub struct ServerImpl { |
401 | @@ -107,7 +105,7 @@ impl Server for ServerImpl { |
402 | } |
403 | |
404 | pub async fn serve(cfg: &Config) -> Result<(), Box<dyn StdError>> { |
405 | - let db = Database::new(&cfg.database.path, false, false).await?; |
406 | + let db = Builder::default().url(&cfg.database.path).build().await?; |
407 | let server = ServerImpl { db: Arc::new(db) }; |
408 | let runtime = CapnpServerHelper::<Client, ServerImpl>::new(&cfg.jobs_socket_path, server); |
409 | runtime.serve().await.map_err(|e| e.into()) |
410 | diff --git a/src/languages.rs b/src/languages.rs |
411 | index 1ddd244..9b236c8 100644 |
412 | --- a/src/languages.rs |
413 | +++ b/src/languages.rs |
414 | @@ -54,6 +54,7 @@ struct Language { |
415 | pub extensions: Option<Vec<String>>, |
416 | pub filenames: Option<Vec<String>>, |
417 | pub aliases: Option<Vec<String>>, |
418 | + #[allow(dead_code)] |
419 | #[serde(rename = "codemirror_mime_type")] |
420 | pub mime_type: Option<String>, |
421 | } |
422 | @@ -174,8 +175,8 @@ impl Languages { |
423 | let mut split = line.split(' '); |
424 | let first = split.nth(0).unwrap(); |
425 | let path = Path::new(first.trim_start_matches("#!")); |
426 | - match path.file_name() { |
427 | - Some(name) => match name.to_str().unwrap() { |
428 | + if let Some(name) = path.file_name() { |
429 | + match name.to_str().unwrap() { |
430 | "env" => { |
431 | // special case for env shebang where the input |
432 | // uses an -S arg, see man env.1 |
433 | @@ -201,8 +202,7 @@ impl Languages { |
434 | } |
435 | } |
436 | name => return Some(Hint(name.to_string())), |
437 | - }, |
438 | - None => {} |
439 | + } |
440 | } |
441 | } |
442 | } |
443 | diff --git a/src/web2/highlight.rs b/src/web2/highlight.rs |
444 | index 5dada46..462c804 100644 |
445 | --- a/src/web2/highlight.rs |
446 | +++ b/src/web2/highlight.rs |
447 | @@ -9,9 +9,9 @@ use std::sync::RwLock; |
448 | use comrak::adapters::SyntaxHighlighterAdapter; |
449 | use lazy_static::lazy_static; |
450 | use log::debug; |
451 | - use tree_sitter_highlight::{HighlightConfiguration, Highlighter as TSHighlighter, HtmlRenderer}; |
452 | - use tree_sitter::Language; |
453 | use tera::escape_html; |
454 | + use tree_sitter::Language; |
455 | + use tree_sitter_highlight::{HighlightConfiguration, Highlighter as TSHighlighter, HtmlRenderer}; |
456 | |
457 | use crate::config::TreeSitterParser; |
458 | use crate::languages::{Hint, LANGUAGE_TABLE}; |
459 | @@ -78,39 +78,36 @@ impl Loader { |
460 | |
461 | fn try_query_load(&self, path: &str, hint: &Hint) -> Result<(), Error> { |
462 | let query_base_path = Path::new(path).join(hint.0.to_string().to_lowercase()); |
463 | - match fs::read_dir(query_base_path) { |
464 | - Ok(queries) => { |
465 | - for query in queries { |
466 | - let query = query?; |
467 | - match query.file_name().into_string().unwrap().as_str() { |
468 | - "highlights.scm" => { |
469 | - let highlight_scm = fs::read_to_string(query.path())?; |
470 | - HIGHLIGHTS |
471 | - .write() |
472 | - .unwrap() |
473 | - .insert(hint.clone(), highlight_scm); |
474 | - debug!("loaded [{:?}] {}", hint, query.path().display()); |
475 | - } |
476 | - "locals.scm" => { |
477 | - let locals_scm = fs::read_to_string(query.path())?; |
478 | - LOCALS.write().unwrap().insert(hint.clone(), locals_scm); |
479 | - debug!("loaded [{:?}] {}", hint, query.path().display()); |
480 | - } |
481 | - "injections.scm" => { |
482 | - let injections_scm = fs::read_to_string(query.path())?; |
483 | - INJECTIONS |
484 | - .write() |
485 | - .unwrap() |
486 | - .insert(hint.clone(), injections_scm); |
487 | - debug!("loaded [{:?}] {}", hint, query.path().display()); |
488 | - } |
489 | - name => { |
490 | - debug!("ignoring query file: {}", name) |
491 | - } |
492 | + if let Ok(queries) = fs::read_dir(query_base_path) { |
493 | + for query in queries { |
494 | + let query = query?; |
495 | + match query.file_name().into_string().unwrap().as_str() { |
496 | + "highlights.scm" => { |
497 | + let highlight_scm = fs::read_to_string(query.path())?; |
498 | + HIGHLIGHTS |
499 | + .write() |
500 | + .unwrap() |
501 | + .insert(hint.clone(), highlight_scm); |
502 | + debug!("loaded [{:?}] {}", hint, query.path().display()); |
503 | + } |
504 | + "locals.scm" => { |
505 | + let locals_scm = fs::read_to_string(query.path())?; |
506 | + LOCALS.write().unwrap().insert(hint.clone(), locals_scm); |
507 | + debug!("loaded [{:?}] {}", hint, query.path().display()); |
508 | + } |
509 | + "injections.scm" => { |
510 | + let injections_scm = fs::read_to_string(query.path())?; |
511 | + INJECTIONS |
512 | + .write() |
513 | + .unwrap() |
514 | + .insert(hint.clone(), injections_scm); |
515 | + debug!("loaded [{:?}] {}", hint, query.path().display()); |
516 | + } |
517 | + name => { |
518 | + debug!("ignoring query file: {}", name) |
519 | } |
520 | } |
521 | } |
522 | - Err(_) => {} |
523 | } |
524 | Ok(()) |
525 | } |
526 | @@ -181,6 +178,21 @@ impl Loader { |
527 | } |
528 | } |
529 | |
530 | + fn render_lines(lines: Vec<&str>, show_line_numbers: bool) -> String { |
531 | + let buf = Vec::new(); |
532 | + let mut file = Cursor::new(buf); |
533 | + write!(&mut file, "<table>").unwrap(); |
534 | + for (i, line) in lines.into_iter().enumerate() { |
535 | + if show_line_numbers { |
536 | + write!(&mut file, "<tr><td class=line-number>{:?}</td>", i + 1).unwrap(); |
537 | + } |
538 | + write!(&mut file, "<td class=line>{}</td></tr>", line).unwrap(); |
539 | + } |
540 | + write!(&mut file, "</table>").unwrap(); |
541 | + let bytes = file.into_inner(); |
542 | + String::from_utf8(bytes).unwrap() |
543 | + } |
544 | + |
545 | #[derive(Clone, Debug)] |
546 | pub struct Highlighter { |
547 | names: Vec<String>, |
548 | @@ -200,21 +212,6 @@ impl Highlighter { |
549 | } |
550 | } |
551 | |
552 | - fn from_lines(&self, lines: Vec<&str>, show_line_numbers: bool) -> String { |
553 | - let buf = Vec::new(); |
554 | - let mut file = Cursor::new(buf); |
555 | - write!(&mut file, "<table>").unwrap(); |
556 | - for (i, line) in lines.into_iter().enumerate() { |
557 | - if show_line_numbers { |
558 | - write!(&mut file, "<tr><td class=line-number>{:?}</td>", i + 1).unwrap(); |
559 | - } |
560 | - write!(&mut file, "<td class=line>{}</td></tr>", line).unwrap(); |
561 | - } |
562 | - write!(&mut file, "</table>").unwrap(); |
563 | - let bytes = file.into_inner(); |
564 | - String::from_utf8(bytes).unwrap() |
565 | - } |
566 | - |
567 | pub fn highlight( |
568 | &self, |
569 | code: &str, |
570 | @@ -245,12 +242,14 @@ impl Highlighter { |
571 | let injections = INJECTIONS |
572 | .read() |
573 | .unwrap() |
574 | - .get(&hint).cloned() |
575 | + .get(&hint) |
576 | + .cloned() |
577 | .unwrap_or_default(); |
578 | let locals = LOCALS |
579 | .read() |
580 | .unwrap() |
581 | - .get(&hint).cloned() |
582 | + .get(&hint) |
583 | + .cloned() |
584 | .unwrap_or_default(); |
585 | let mut config = |
586 | HighlightConfiguration::new(*language, syntax, &injections, &locals) |
587 | @@ -278,20 +277,14 @@ impl Highlighter { |
588 | |
589 | ( |
590 | Some(hint.clone()), |
591 | - self.from_lines( |
592 | - renderer.lines().collect(), |
593 | - show_line_numbers, |
594 | - ), |
595 | + render_lines(renderer.lines().collect(), show_line_numbers), |
596 | ) |
597 | } |
598 | _ => { |
599 | debug!("cannot paint syntax for language: {:?}", hint); |
600 | ( |
601 | None, |
602 | - self.from_lines( |
603 | - escape_html(code).lines().collect(), |
604 | - show_line_numbers, |
605 | - ), |
606 | + render_lines(escape_html(code).lines().collect(), show_line_numbers), |
607 | ) |
608 | } |
609 | }, |
610 | @@ -299,10 +292,7 @@ impl Highlighter { |
611 | debug!("cannot determine language"); |
612 | ( |
613 | None, |
614 | - self.from_lines( |
615 | - code.to_string().lines().collect(), |
616 | - show_line_numbers, |
617 | - ), |
618 | + render_lines(code.to_string().lines().collect(), show_line_numbers), |
619 | ) |
620 | } |
621 | } |
622 | diff --git a/src/web2/middleware/error.rs b/src/web2/middleware/error.rs |
623 | index cecd638..956589e 100644 |
624 | --- a/src/web2/middleware/error.rs |
625 | +++ b/src/web2/middleware/error.rs |
626 | @@ -1,8 +1,7 @@ |
627 | - |
628 | use std::sync::Arc; |
629 | |
630 | use axum::{ |
631 | - extract::{Request, State}, |
632 | + extract, |
633 | http::StatusCode, |
634 | middleware::Next, |
635 | response::{Html, IntoResponse, Response}, |
636 | @@ -14,10 +13,12 @@ use crate::web2::error::Error; |
637 | use crate::web2::extractors::config::ConfigReader; |
638 | use crate::web2::terautil::{Loader, Options}; |
639 | |
640 | + pub type State = Arc<(Config, Vec<(String, Tera)>)>; |
641 | + |
642 | pub async fn middleware( |
643 | - State(state): State<Arc<(Config, Vec<(String, Tera)>)>>, |
644 | + extract::State(state): extract::State<State>, |
645 | ConfigReader(client_config): ConfigReader, |
646 | - req: Request, |
647 | + req: extract::Request, |
648 | next: Next, |
649 | ) -> Response { |
650 | let response = next.run(req).await; |
651 | diff --git a/src/web2/middleware/rpc_initiator.rs b/src/web2/middleware/rpc_initiator.rs |
652 | index 78d2642..cdc455c 100644 |
653 | --- a/src/web2/middleware/rpc_initiator.rs |
654 | +++ b/src/web2/middleware/rpc_initiator.rs |
655 | @@ -3,7 +3,7 @@ use std::sync::Arc; |
656 | use crate::web2::terautil::{Loader, Options}; |
657 | use axum::{ |
658 | body::Body, |
659 | - extract::{Request, State}, |
660 | + extract, |
661 | http::{header::CONTENT_TYPE, StatusCode}, |
662 | middleware::Next, |
663 | response::Response, |
664 | @@ -17,6 +17,8 @@ use crate::web2::config::Config as ClientConfig; |
665 | use crate::web2::extractors::config::ConfigReader; |
666 | use ayllu_rpc::Client; |
667 | |
668 | + pub type State = Arc<(Config, Vec<(String, Tera)>, &'static [Kind])>; |
669 | + |
670 | pub enum Kind { |
671 | Mail, |
672 | Xmpp, |
673 | @@ -41,12 +43,12 @@ fn plugin_not_enabled( |
674 | plugin_name: &str, |
675 | cfg: &Config, |
676 | client_config: ClientConfig, |
677 | - templates: &Vec<(String, Tera)>, |
678 | + templates: &[(String, Tera)], |
679 | ) -> Response { |
680 | log::warn!("returning error due to missing plugin: {}", plugin_name); |
681 | // reload the theme since the middleware may not have ran yet |
682 | let loader = Loader { |
683 | - templates: templates.clone(), |
684 | + templates: templates.to_vec(), |
685 | default_theme: cfg.web.default_theme.clone(), |
686 | }; |
687 | let (template, mut ctx) = loader.load( |
688 | @@ -71,7 +73,11 @@ fn plugin_not_enabled( |
689 | } |
690 | |
691 | /// configure an optinoal plugin for use in a handler |
692 | - pub async fn optional(State(cfg): State<Arc<Config>>, mut req: Request, next: Next) -> Response { |
693 | + pub async fn optional( |
694 | + extract::State(cfg): extract::State<Arc<Config>>, |
695 | + mut req: extract::Request, |
696 | + next: Next, |
697 | + ) -> Response { |
698 | req.extensions_mut().insert(Initiator { |
699 | mail: cfg |
700 | |
701 | @@ -88,9 +94,9 @@ pub async fn optional(State(cfg): State<Arc<Config>>, mut req: Request, next: Ne |
702 | /// configure a required plugin for use in a handler, if it is not configured |
703 | /// an error page will be returned from the handler |
704 | pub async fn required( |
705 | - State(state): State<Arc<(Config, Vec<(String, Tera)>, &'static [Kind])>>, |
706 | + extract::State(state): extract::State<State>, |
707 | ConfigReader(client_config): ConfigReader, |
708 | - mut req: Request, |
709 | + mut req: extract::Request, |
710 | next: Next, |
711 | ) -> Response { |
712 | let mut initiator = Initiator::default(); |
713 | diff --git a/src/web2/middleware/sites.rs b/src/web2/middleware/sites.rs |
714 | index eecd85b..c711298 100644 |
715 | --- a/src/web2/middleware/sites.rs |
716 | +++ b/src/web2/middleware/sites.rs |
717 | @@ -3,7 +3,7 @@ use std::path::{Path, PathBuf}; |
718 | |
719 | use axum::{ |
720 | body::Body, |
721 | - extract::{Request, State}, |
722 | + extract, |
723 | http::{header, StatusCode}, |
724 | middleware::Next, |
725 | response::{IntoResponse, Response}, |
726 | @@ -16,6 +16,9 @@ use crate::web2::error::Error; |
727 | use crate::web2::util; |
728 | use ayllu_git::Wrapper as Repository; |
729 | |
730 | + pub type State = extract::State<(Config, Vec<(String, (String, String))>)>; |
731 | + pub type Sites = Vec<(String, (String, String))>; |
732 | + |
733 | // array of all the repositories in each collection |
734 | fn repositories(collections: Vec<Collection>) -> Result<Vec<PathBuf>, Error> { |
735 | let mut paths: Vec<PathBuf> = Vec::new(); |
736 | @@ -32,7 +35,7 @@ fn repositories(collections: Vec<Collection>) -> Result<Vec<PathBuf>, Error> { |
737 | Ok(paths) |
738 | } |
739 | |
740 | - pub fn sites(cfg: Config) -> Result<Vec<(String, (String, String))>, Error> { |
741 | + pub fn sites(cfg: Config) -> Result<Sites, Error> { |
742 | let mut sites: Vec<(String, (String, String))> = Vec::new(); |
743 | for path in repositories(cfg.collections.clone())? { |
744 | let repository = Repository::new(path.as_path())?; |
745 | @@ -53,8 +56,8 @@ pub fn sites(cfg: Config) -> Result<Vec<(String, (String, String))>, Error> { |
746 | } |
747 | |
748 | pub async fn middleware( |
749 | - State((cfg, sites)): State<(Config, Vec<(String, (String, String))>)>, |
750 | - req: Request, |
751 | + extract::State((cfg, sites)): State, |
752 | + req: extract::Request, |
753 | next: Next, |
754 | ) -> Result<Response, Error> { |
755 | if !cfg.sites.enabled { |
756 | @@ -82,7 +85,7 @@ pub async fn middleware( |
757 | |
758 | match repo_path { |
759 | Some(repo_path) => { |
760 | - let repository = Repository::from_str(&repo_path)?; |
761 | + let repository = Repository::new(Path::new(&repo_path))?; |
762 | let config = repository.config()?; |
763 | let path = util::select_path(req.uri(), Some(0), None).map_or_else( |
764 | || PathBuf::from("index.html"), |
765 | diff --git a/src/web2/middleware/template.rs b/src/web2/middleware/template.rs |
766 | index e93c093..58f93cc 100644 |
767 | --- a/src/web2/middleware/template.rs |
768 | +++ b/src/web2/middleware/template.rs |
769 | @@ -2,18 +2,14 @@ use serde::Deserialize; |
770 | use std::sync::Arc; |
771 | use tera::{Context as TeraContext, Tera}; |
772 | |
773 | - use axum::{ |
774 | - extract::Request, |
775 | - extract::{Path, State}, |
776 | - middleware::Next, |
777 | - response::Response, |
778 | - }; |
779 | + use axum::{extract, middleware::Next, response::Response}; |
780 | |
781 | use crate::config::Config; |
782 | use crate::web2::extractors::config::ConfigReader; |
783 | use crate::web2::terautil::{Loader, Options}; |
784 | |
785 | pub type Template = (Tera, TeraContext); |
786 | + pub type State = extract::State<Arc<(Config, Vec<(String, Tera)>)>>; |
787 | |
788 | #[derive(Deserialize)] |
789 | pub struct CommonParams { |
790 | @@ -22,10 +18,10 @@ pub struct CommonParams { |
791 | } |
792 | |
793 | pub async fn middleware( |
794 | - State(state): State<Arc<(Config, Vec<(String, Tera)>)>>, |
795 | + extract::State(state): State, |
796 | ConfigReader(config): ConfigReader, |
797 | - Path(CommonParams { collection, name }): Path<CommonParams>, |
798 | - mut req: Request, |
799 | + extract::Path(CommonParams { collection, name }): extract::Path<CommonParams>, |
800 | + mut req: extract::Request, |
801 | next: Next, |
802 | ) -> Response { |
803 | let loader = Loader { |
804 | diff --git a/src/web2/routes/blob.rs b/src/web2/routes/blob.rs |
805 | index cc0dbad..9cb8fff 100644 |
806 | --- a/src/web2/routes/blob.rs |
807 | +++ b/src/web2/routes/blob.rs |
808 | @@ -76,12 +76,9 @@ pub async fn serve( |
809 | let file_path = preamble.file_path_string(); |
810 | let (hint, content) = |
811 | highlighter.highlight(&content, Some(file_path.as_str()), None, None, true); |
812 | - match hint { |
813 | - Some(hint) => { |
814 | - ctx.insert("color", &LANGUAGE_TABLE.color_from_language(&hint)); |
815 | - ctx.insert("hint", &hint); |
816 | - } |
817 | - None => {} |
818 | + if let Some(hint) = hint { |
819 | + ctx.insert("color", &LANGUAGE_TABLE.color_from_language(&hint)); |
820 | + ctx.insert("hint", &hint); |
821 | } |
822 | ctx.insert("content", &content); |
823 | } |
824 | diff --git a/src/web2/routes/repo.rs b/src/web2/routes/repo.rs |
825 | index 4a5102d..4482e9b 100644 |
826 | --- a/src/web2/routes/repo.rs |
827 | +++ b/src/web2/routes/repo.rs |
828 | @@ -147,45 +147,42 @@ async fn managed_chats(cfg: &Config, git_cfg: &GitConfig, initiator: Initiator) |
829 | } |
830 | } |
831 | let xmpp_client = initiator.client(InitiatorKind::Xmpp); |
832 | - match xmpp_client { |
833 | - Some(xmpp_client) => { |
834 | - match xmpp_client |
835 | - .invoke(move |client: XmppClient| async move { |
836 | - let mut remote_channels: Vec<ChatLink> = Vec::new(); |
837 | - let mut request = client.stats_request(); |
838 | - let mut channels = request |
839 | - .get() |
840 | - .init_channels(managed_xmpp_channels.len() as u32); |
841 | - for (i, lookup) in to_lookup.iter().enumerate() { |
842 | - channels.set(i as u32, lookup.as_str().into()); |
843 | - } |
844 | - let status = request.send().promise.await?; |
845 | - let results = status.get()?; |
846 | - let stats = results.get_stats()?; |
847 | - for stat in stats { |
848 | - remote_channels.push(ChatLink { |
849 | - kind: format!("{:?}", ChatKind::Xmpp), |
850 | - url: stat.get_name()?.to_string().unwrap(), |
851 | - description: None, |
852 | - users_online: Some(stat.get_users_online()), |
853 | - }) |
854 | - } |
855 | - Ok(remote_channels) |
856 | - }) |
857 | - .await |
858 | - { |
859 | - Ok(remote_links) => { |
860 | - links.extend(remote_links); |
861 | + if let Some(xmpp_client) = xmpp_client { |
862 | + match xmpp_client |
863 | + .invoke(move |client: XmppClient| async move { |
864 | + let mut remote_channels: Vec<ChatLink> = Vec::new(); |
865 | + let mut request = client.stats_request(); |
866 | + let mut channels = request |
867 | + .get() |
868 | + .init_channels(managed_xmpp_channels.len() as u32); |
869 | + for (i, lookup) in to_lookup.iter().enumerate() { |
870 | + channels.set(i as u32, lookup.as_str().into()); |
871 | } |
872 | - Err(err) => { |
873 | - log::error!( |
874 | - "failed to resolve discussion group status: {:?}", |
875 | - err.to_string() |
876 | - ) |
877 | + let status = request.send().promise.await?; |
878 | + let results = status.get()?; |
879 | + let stats = results.get_stats()?; |
880 | + for stat in stats { |
881 | + remote_channels.push(ChatLink { |
882 | + kind: format!("{:?}", ChatKind::Xmpp), |
883 | + url: stat.get_name()?.to_string().unwrap(), |
884 | + description: None, |
885 | + users_online: Some(stat.get_users_online()), |
886 | + }) |
887 | } |
888 | - }; |
889 | - } |
890 | - None => {} |
891 | + Ok(remote_channels) |
892 | + }) |
893 | + .await |
894 | + { |
895 | + Ok(remote_links) => { |
896 | + links.extend(remote_links); |
897 | + } |
898 | + Err(err) => { |
899 | + log::error!( |
900 | + "failed to resolve discussion group status: {:?}", |
901 | + err.to_string() |
902 | + ) |
903 | + } |
904 | + }; |
905 | } |
906 | } |
907 | links |
908 | diff --git a/src/web2/routes/rss.rs b/src/web2/routes/rss.rs |
909 | index 8a1387b..2597a6d 100644 |
910 | --- a/src/web2/routes/rss.rs |
911 | +++ b/src/web2/routes/rss.rs |
912 | @@ -41,9 +41,9 @@ fn html_commit(summary: String, message: String) -> String { |
913 | /// Timeframe specifies a chunk of time to summarize repository activity for. |
914 | #[derive(Clone, Copy)] |
915 | enum Timeframe { |
916 | - DAILY, |
917 | - WEEKLY, |
918 | - MONTHLY, |
919 | + Daily, |
920 | + Weekly, |
921 | + Monthly, |
922 | } |
923 | |
924 | impl Timeframe { |
925 | @@ -53,14 +53,14 @@ impl Timeframe { |
926 | /// 7 day week from the "current" week. |
927 | pub fn clamp(self, current_time: OffsetDateTime) -> (OffsetDateTime, OffsetDateTime) { |
928 | match self { |
929 | - Timeframe::DAILY => { |
930 | + Timeframe::Daily => { |
931 | // today at midnight |
932 | let end_time = current_time.replace_time(time!(00:00:00)); |
933 | // 00:00:00 two days ago |
934 | let start_time = end_time.saturating_sub(24 * Duration::HOUR); |
935 | (start_time, end_time) |
936 | } |
937 | - Timeframe::WEEKLY => { |
938 | + Timeframe::Weekly => { |
939 | // today at midnight |
940 | let current_time = current_time.replace_time(time!(00:00:00)); |
941 | // days to previous sunday |
942 | @@ -70,7 +70,7 @@ impl Timeframe { |
943 | let start_time = end_time.saturating_sub(7 * Duration::DAY); |
944 | (start_time, end_time) |
945 | } |
946 | - Timeframe::MONTHLY => { |
947 | + Timeframe::Monthly => { |
948 | // today at midnight |
949 | let current_time = current_time.replace_time(time!(00:00:00)); |
950 | let days_to_previous_month = current_time.date().day(); |
951 | @@ -133,11 +133,8 @@ impl Builder { |
952 | .map_or(String::new(), |date| date.to_string()) |
953 | })); |
954 | channel.set_items(items); |
955 | - match self.time_to_live { |
956 | - Some(ttl) => { |
957 | - channel.set_ttl(ttl.whole_minutes().to_string()); |
958 | - } |
959 | - None => {} |
960 | + if let Some(ttl) = self.time_to_live { |
961 | + channel.set_ttl(ttl.whole_minutes().to_string()); |
962 | } |
963 | channel |
964 | } |
965 | @@ -295,9 +292,7 @@ pub async fn feed_firehose( |
966 | context, |
967 | origin: cfg.origin, |
968 | title: String::from("Firehose"), |
969 | - time_to_live: cfg |
970 | - .rss_time_to_live |
971 | - .map(Duration::seconds), |
972 | + time_to_live: cfg.rss_time_to_live.map(Duration::seconds), |
973 | current_time: OffsetDateTime::now_utc(), |
974 | }; |
975 | let channel = builder.firehose( |
976 | @@ -320,14 +315,12 @@ pub async fn feed_1d( |
977 | context, |
978 | origin: cfg.origin, |
979 | title: String::from("Daily Update Summary"), |
980 | - time_to_live: cfg |
981 | - .rss_time_to_live |
982 | - .map(Duration::seconds), |
983 | + time_to_live: cfg.rss_time_to_live.map(Duration::seconds), |
984 | current_time: OffsetDateTime::now_utc(), |
985 | }; |
986 | let channel = builder.summary( |
987 | builder.scan_repositories(cfg.collections)?, |
988 | - Timeframe::DAILY, |
989 | + Timeframe::Daily, |
990 | )?; |
991 | let response = Response::builder() |
992 | .header(CONTENT_TYPE, TEXT_XML.as_ref()) |
993 | @@ -345,14 +338,12 @@ pub async fn feed_1w( |
994 | context, |
995 | origin: cfg.origin, |
996 | title: String::from("Weekly Update Summary"), |
997 | - time_to_live: cfg |
998 | - .rss_time_to_live |
999 | - .map(Duration::seconds), |
1000 | + time_to_live: cfg.rss_time_to_live.map(Duration::seconds), |
1001 | current_time: OffsetDateTime::now_utc(), |
1002 | }; |
1003 | let channel = builder.summary( |
1004 | builder.scan_repositories(cfg.collections)?, |
1005 | - Timeframe::WEEKLY, |
1006 | + Timeframe::Weekly, |
1007 | )?; |
1008 | let response = Response::builder() |
1009 | .header(CONTENT_TYPE, TEXT_XML.as_ref()) |
1010 | @@ -370,14 +361,12 @@ pub async fn feed_1m( |
1011 | context, |
1012 | origin: cfg.origin, |
1013 | title: String::from("Monthly Update Summary"), |
1014 | - time_to_live: cfg |
1015 | - .rss_time_to_live |
1016 | - .map(Duration::seconds), |
1017 | + time_to_live: cfg.rss_time_to_live.map(Duration::seconds), |
1018 | current_time: OffsetDateTime::now_utc(), |
1019 | }; |
1020 | let channel = builder.summary( |
1021 | builder.scan_repositories(cfg.collections)?, |
1022 | - Timeframe::MONTHLY, |
1023 | + Timeframe::Monthly, |
1024 | )?; |
1025 | let response = Response::builder() |
1026 | .header(CONTENT_TYPE, TEXT_XML.as_ref()) |
1027 | @@ -401,9 +390,7 @@ pub async fn feed_repository_firehose( |
1028 | "Firehose for {}/{}", |
1029 | preamble.collection_name, preamble.repo_name |
1030 | ), |
1031 | - time_to_live: cfg |
1032 | - .rss_time_to_live |
1033 | - .map(Duration::seconds), |
1034 | + time_to_live: cfg.rss_time_to_live.map(Duration::seconds), |
1035 | current_time: OffsetDateTime::now_utc(), |
1036 | }; |
1037 | let channel = builder.firehose(vec![(preamble.repo_path, project_url)], Duration::days(7))?; |
1038 | @@ -429,12 +416,10 @@ pub async fn feed_repository_1d( |
1039 | "Daily Update Summary for {}/{}", |
1040 | preamble.collection_name, preamble.repo_name |
1041 | ), |
1042 | - time_to_live: cfg |
1043 | - .rss_time_to_live |
1044 | - .map(Duration::seconds), |
1045 | + time_to_live: cfg.rss_time_to_live.map(Duration::seconds), |
1046 | current_time: OffsetDateTime::now_utc(), |
1047 | }; |
1048 | - let channel = builder.summary(vec![(preamble.repo_path, project_url)], Timeframe::DAILY)?; |
1049 | + let channel = builder.summary(vec![(preamble.repo_path, project_url)], Timeframe::Daily)?; |
1050 | let response = Response::builder() |
1051 | .header(CONTENT_TYPE, TEXT_XML.as_ref()) |
1052 | .body(Body::new(stylesheet_hack(channel.to_string()))) |
1053 | @@ -457,12 +442,10 @@ pub async fn feed_repository_1w( |
1054 | "Weekly Update Summary for {}/{}", |
1055 | preamble.collection_name, preamble.repo_name |
1056 | ), |
1057 | - time_to_live: cfg |
1058 | - .rss_time_to_live |
1059 | - .map(Duration::seconds), |
1060 | + time_to_live: cfg.rss_time_to_live.map(Duration::seconds), |
1061 | current_time: OffsetDateTime::now_utc(), |
1062 | }; |
1063 | - let channel = builder.summary(vec![(preamble.repo_path, project_url)], Timeframe::WEEKLY)?; |
1064 | + let channel = builder.summary(vec![(preamble.repo_path, project_url)], Timeframe::Weekly)?; |
1065 | let response = Response::builder() |
1066 | .header(CONTENT_TYPE, TEXT_XML.as_ref()) |
1067 | .body(Body::new(stylesheet_hack(channel.to_string()))) |
1068 | @@ -485,12 +468,10 @@ pub async fn feed_repository_1m( |
1069 | "Monthly Update Summary for {}/{}", |
1070 | preamble.collection_name, preamble.repo_name |
1071 | ), |
1072 | - time_to_live: cfg |
1073 | - .rss_time_to_live |
1074 | - .map(Duration::seconds), |
1075 | + time_to_live: cfg.rss_time_to_live.map(Duration::seconds), |
1076 | current_time: OffsetDateTime::now_utc(), |
1077 | }; |
1078 | - let channel = builder.summary(vec![(preamble.repo_path, project_url)], Timeframe::MONTHLY)?; |
1079 | + let channel = builder.summary(vec![(preamble.repo_path, project_url)], Timeframe::Monthly)?; |
1080 | let response = Response::builder() |
1081 | .header(CONTENT_TYPE, TEXT_XML.as_ref()) |
1082 | .body(Body::new(stylesheet_hack(channel.to_string()))) |
1083 | @@ -612,7 +593,7 @@ mod tests { |
1084 | .as_ref() |
1085 | .is_some_and(|title| title == "Commit: commit 1")); |
1086 | assert!(channel.items[0].guid.is_some()); |
1087 | - // FIXME: assert!(channel.items[1].guid.is_some()); |
1088 | + // FIXME: assert!(channel.items[1].guid.is_some()); |
1089 | assert!(channel.items[2].guid.is_some()); |
1090 | test_repo.cleanup().expect("failed to cleanup repo"); |
1091 | } |
1092 | @@ -650,7 +631,7 @@ mod tests { |
1093 | current_time: OffsetDateTime::parse(CURRENT_TIME, &Rfc2822).unwrap(), |
1094 | }; |
1095 | let channel = builder |
1096 | - .summary(vec![(path, name)], Timeframe::DAILY) |
1097 | + .summary(vec![(path, name)], Timeframe::Daily) |
1098 | .expect("failed to build items"); |
1099 | assert!(channel.items.len() == 1); |
1100 | assert!(channel.items[0] |
1101 | @@ -688,7 +669,7 @@ mod tests { |
1102 | current_time: OffsetDateTime::parse(CURRENT_TIME, &Rfc2822).unwrap(), |
1103 | }; |
1104 | let channel = builder |
1105 | - .summary(vec![(path, name)], Timeframe::WEEKLY) |
1106 | + .summary(vec![(path, name)], Timeframe::Weekly) |
1107 | .expect("failed to build items"); |
1108 | assert!(channel.items.len() == 1); |
1109 | assert!(channel.items[0] |
1110 | @@ -732,7 +713,7 @@ mod tests { |
1111 | current_time: OffsetDateTime::parse(CURRENT_TIME, &Rfc2822).unwrap(), |
1112 | }; |
1113 | let channel = builder |
1114 | - .summary(vec![(path, name)], Timeframe::MONTHLY) |
1115 | + .summary(vec![(path, name)], Timeframe::Monthly) |
1116 | .expect("failed to build items"); |
1117 | assert!(channel.items.len() == 1); |
1118 | assert!(channel.items[0] |
1119 | @@ -766,7 +747,7 @@ mod tests { |
1120 | current_time: OffsetDateTime::parse(CURRENT_TIME, &Rfc2822).unwrap(), |
1121 | }; |
1122 | let channel = builder |
1123 | - .summary(vec![(path, name)], Timeframe::DAILY) |
1124 | + .summary(vec![(path, name)], Timeframe::Daily) |
1125 | .expect("failed to build items"); |
1126 | assert!(channel.items.is_empty()); |
1127 | assert!(channel.ttl.as_ref().is_some_and(|ttl| ttl == "60")) |
1128 | @@ -775,7 +756,7 @@ mod tests { |
1129 | #[test] |
1130 | fn test_timeframe_1d() { |
1131 | let now = datetime!(2021-03-05 13:00:55 UTC); |
1132 | - let (start, end) = Timeframe::DAILY.clamp(now); |
1133 | + let (start, end) = Timeframe::Daily.clamp(now); |
1134 | assert!(start == datetime!(2021-03-04 00:00:00 UTC)); |
1135 | assert!(end == datetime!(2021-03-05 00:00:00 UTC)); |
1136 | } |
1137 | @@ -783,11 +764,11 @@ mod tests { |
1138 | #[test] |
1139 | fn test_timeframe_1w() { |
1140 | let now = datetime!(2021-03-05 13:00:55 UTC); |
1141 | - let (start, end) = Timeframe::WEEKLY.clamp(now); |
1142 | + let (start, end) = Timeframe::Weekly.clamp(now); |
1143 | assert!(start == datetime!(2021-02-21 00:00:00 UTC)); |
1144 | assert!(end == datetime!(2021-02-28 00:00:00 UTC)); |
1145 | let now = datetime!(2021-03-07 21:34:05 UTC); |
1146 | - let (start, end) = Timeframe::WEEKLY.clamp(now); |
1147 | + let (start, end) = Timeframe::Weekly.clamp(now); |
1148 | assert!(start == datetime!(2021-02-28 00:00:00 UTC)); |
1149 | assert!(end == datetime!(2021-03-07 00:00:00 UTC)); |
1150 | } |
1151 | @@ -795,11 +776,11 @@ mod tests { |
1152 | #[test] |
1153 | fn test_timeframe_1m() { |
1154 | let now = datetime!(2021-03-05 13:00:55 UTC); |
1155 | - let (start, end) = Timeframe::MONTHLY.clamp(now); |
1156 | + let (start, end) = Timeframe::Monthly.clamp(now); |
1157 | assert!(start == datetime!(2021-02-01 00:00:00 UTC)); |
1158 | assert!(end == datetime!(2021-02-28 00:00:00 UTC)); |
1159 | let now = datetime!(2021-01-05 13:00:55 UTC); |
1160 | - let (start, end) = Timeframe::MONTHLY.clamp(now); |
1161 | + let (start, end) = Timeframe::Monthly.clamp(now); |
1162 | assert!(start == datetime!(2020-12-01 00:00:00 UTC)); |
1163 | assert!(end == datetime!(2020-12-31 00:00:00 UTC)); |
1164 | } |
1165 | diff --git a/src/web2/server.rs b/src/web2/server.rs |
1166 | index e8cb16f..60dff65 100644 |
1167 | --- a/src/web2/server.rs |
1168 | +++ b/src/web2/server.rs |
1169 | @@ -46,7 +46,7 @@ use crate::web2::routes::robots; |
1170 | use crate::web2::routes::rss; |
1171 | use crate::web2::routes::xmpp; |
1172 | use crate::web2::terautil; |
1173 | - use ayllu_database::Wrapper as Database; |
1174 | + use ayllu_database::Builder; |
1175 | |
1176 | pub async fn serve(cfg: &Config) -> Result<(), Box<dyn Error>> { |
1177 | let keywords = match &cfg.tree_sitter { |
1178 | @@ -90,12 +90,12 @@ pub async fn serve(cfg: &Config) -> Result<(), Box<dyn Error>> { |
1179 | let highlighter = Highlighter::new(&keywords); |
1180 | let adapter = TreeSitterAdapter::new(highlighter.clone()); |
1181 | |
1182 | - let db = Database::new( |
1183 | - &cfg.database.path, |
1184 | - cfg.database.migrate, |
1185 | - cfg.log_level == "DEBUG", |
1186 | - ) |
1187 | - .await?; |
1188 | + let db = Builder::default() |
1189 | + .url(&cfg.database.path) |
1190 | + .log_queries(cfg.log_level == "DEBUG") |
1191 | + .read_only(true) // Web UI is 100% read-only |
1192 | + .build() |
1193 | + .await?; |
1194 | |
1195 | // NOTE: files modified on the file system will see their changes |
1196 | // immediately in the rendered server output however added new files |