nextcloud_route_extractor/
lib.rs

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