nextcloud_route_extractor/
lib.rs

1use crate::attribute_routes::extract_attribute_routes;
2use crate::routes_php::extract_routes_php;
3use glob::{glob, GlobError, Paths, Pattern};
4use std::fs::read_to_string;
5use std::path::{Path, PathBuf};
6use thiserror::Error;
7
8mod attribute_routes;
9mod route;
10mod routes_php;
11
12pub use route::*;
13
14pub fn core_routes(path: &str) -> Result<AppRoutes, Error> {
15    let mut result = AppRoutes {
16        routes: vec![
17            Route {
18                url: "/core/ajax/update.php".into(),
19                name: "core#ajax_update".into(),
20                ..Route::default()
21            },
22            Route {
23                url: "/heartbeat".into(),
24                name: "core#heartbeat".into(),
25                ..Route::default()
26            },
27        ],
28        ocs: vec![],
29    };
30
31    let controller_paths = glob(&format!(
32        "{}/core/Controller/*Controller.php",
33        Pattern::escape(path)
34    ))
35    .unwrap();
36    for routes in extract_controllers(controller_paths) {
37        let routes = routes?;
38        result.routes.extend_from_slice(&routes.routes);
39        result.ocs.extend_from_slice(&routes.ocs);
40    }
41    Ok(result)
42}
43
44pub fn app_routes(path: &str) -> Result<AppRoutes, Error> {
45    let routes_php_path = <str as AsRef<Path>>::as_ref(path).join("appinfo/routes.php");
46    let mut result = if routes_php_path.exists() {
47        let routes_php = read_to_string(&routes_php_path).map_err(|error| Error::Read {
48            path: routes_php_path.clone(),
49            error,
50        })?;
51        extract_routes_php(&routes_php_path, &routes_php)
52    } else {
53        AppRoutes::default()
54    };
55
56    let controller_paths = glob(&format!(
57        "{}/lib/Controller/*Controller.php",
58        Pattern::escape(path)
59    ))
60    .unwrap();
61    for routes in extract_controllers(controller_paths) {
62        let routes = routes?;
63        result.routes.extend_from_slice(&routes.routes);
64        result.ocs.extend_from_slice(&routes.ocs);
65    }
66    Ok(result)
67}
68
69fn extract_controllers(paths: Paths) -> impl Iterator<Item = Result<AppRoutes, Error>> {
70    paths.map(|controller_path| {
71        let controller_path = controller_path.map_err(Error::Glob)?;
72        let controller_code = read_to_string(&controller_path).map_err(|error| Error::Read {
73            path: controller_path,
74            error,
75        })?;
76        Ok(extract_attribute_routes(&controller_code))
77    })
78}
79
80#[derive(Debug, Error)]
81pub enum Error {
82    #[error("Failed to read {path}: {error:#}")]
83    Read {
84        path: PathBuf,
85        error: std::io::Error,
86    },
87    #[error("Failed to find controller paths: {0:#}")]
88    Glob(GlobError),
89}