polyhorn_cli/android/tasks/
generate_source_tree.rs

1use super::{AndroidContext, AndroidError};
2use crate::core::{Manager, Task};
3use crate::template::SourceTree;
4
5/// This task generates a new source tree based on the template that ships with
6/// `polyhorn-cli`.
7pub struct GenerateSourceTree;
8
9impl Task for GenerateSourceTree {
10    type Context = AndroidContext;
11    type Error = AndroidError;
12
13    fn verb(&self) -> &str {
14        "Generating"
15    }
16
17    fn message(&self) -> &str {
18        "source tree"
19    }
20
21    fn detail(&self) -> &str {
22        "for Android"
23    }
24
25    fn run(
26        &self,
27        context: AndroidContext,
28        manager: &mut Manager,
29    ) -> Result<AndroidContext, AndroidError> {
30        let package_dir = context.config.spec.app.android.package.replace(".", "/");
31
32        let mut tree = SourceTree::new();
33
34        macro_rules! template {
35            ($tree:ident, $path:literal) => {
36                tree.template(
37                    $path,
38                    include_str!(concat!(
39                        env!("CARGO_MANIFEST_DIR"),
40                        "/android/template/",
41                        $path,
42                    )),
43                );
44            };
45        }
46
47        macro_rules! copy {
48            ($tree:ident, $path:literal) => {
49                tree.copy(
50                    $path,
51                    include_bytes!(concat!(
52                        env!("CARGO_MANIFEST_DIR"),
53                        "/android/template/",
54                        $path,
55                    )),
56                );
57            };
58        }
59
60        tree.template(
61            &format!("app/src/main/java/{}/MainActivity.java", package_dir),
62            include_str!(concat!(
63                env!("CARGO_MANIFEST_DIR"),
64                "/android/template/",
65                "app/src/main/java/com/example/myapplication/MainActivity.java"
66            )),
67        );
68
69        copy!(tree, "build.gradle");
70        copy!(tree, "gradle.properties");
71        copy!(tree, "gradlew");
72        copy!(tree, "gradlew.bat");
73        template!(tree, "settings.gradle");
74        template!(tree, "app/build.gradle");
75        template!(tree, "app/src/main/AndroidManifest.xml");
76        copy!(tree, "app/src/main/res/drawable/ic_launcher_background.xml");
77        copy!(
78            tree,
79            "app/src/main/res/drawable-v24/ic_launcher_foreground.xml"
80        );
81        copy!(tree, "app/src/main/res/layout/activity_main.xml");
82        copy!(tree, "app/src/main/res/layout/content_main.xml");
83        template!(tree, "app/src/main/res/menu/menu_main.xml");
84        copy!(
85            tree,
86            "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml"
87        );
88        copy!(tree, "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml");
89        copy!(tree, "app/src/main/res/mipmap-hdpi/ic_launcher_round.png");
90        copy!(tree, "app/src/main/res/mipmap-hdpi/ic_launcher.png");
91        copy!(tree, "app/src/main/res/mipmap-mdpi/ic_launcher_round.png");
92        copy!(tree, "app/src/main/res/mipmap-mdpi/ic_launcher.png");
93        copy!(tree, "app/src/main/res/mipmap-xhdpi/ic_launcher_round.png");
94        copy!(tree, "app/src/main/res/mipmap-xhdpi/ic_launcher.png");
95        copy!(tree, "app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png");
96        copy!(tree, "app/src/main/res/mipmap-xxhdpi/ic_launcher.png");
97        copy!(
98            tree,
99            "app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png"
100        );
101        copy!(tree, "app/src/main/res/mipmap-xxxhdpi/ic_launcher.png");
102        copy!(tree, "app/src/main/res/values/colors.xml");
103        copy!(tree, "app/src/main/res/values/dimens.xml");
104        copy!(tree, "app/src/main/res/values/strings.xml");
105        copy!(tree, "app/src/main/res/values/themes.xml");
106        copy!(tree, "app/src/main/res/values-night/themes.xml");
107        copy!(tree, "app/proguard-rules.pro");
108        copy!(tree, "gradle/wrapper/gradle-wrapper.jar");
109        copy!(tree, "gradle/wrapper/gradle-wrapper.properties");
110
111        let bar = manager.progress_bar(tree.len());
112
113        let mut destination_path = context.config.target_dir.clone();
114        destination_path.push("polyhorn-android");
115
116        for result in tree.generate(&context.config.spec, &destination_path) {
117            bar.inc(1);
118
119            match result {
120                Ok(_) => {}
121                Err(error) => {
122                    eprintln!("Encountered an error: {:#?}", error);
123                    std::process::abort();
124                }
125            }
126        }
127
128        #[cfg(unix)]
129        {
130            use std::fs::File;
131            use std::os::unix::fs::PermissionsExt;
132
133            let mut gradlew_path = destination_path.clone();
134            gradlew_path.push("gradlew");
135            let gradlew = File::open(gradlew_path).unwrap();
136            let mut permissions = gradlew.metadata().unwrap().permissions();
137            permissions.set_mode(0o744);
138            gradlew.set_permissions(permissions).unwrap();
139        }
140
141        bar.finish_and_clear();
142
143        Ok(context)
144    }
145}