libgir/codegen/sys/
cargo_toml.rs
1use std::{collections::HashMap, fs::File, io::prelude::*};
2
3use log::info;
4use toml::{self, value::Table, Value};
5
6use super::collect_versions;
7use crate::{config::Config, env::Env, file_saver::save_to_file, nameutil, version::Version};
8
9pub fn generate(env: &Env) -> String {
10 info!("Generating sys Cargo.toml for {}", env.config.library_name);
11
12 let path = env.config.target_path.join("Cargo.toml");
13
14 let mut toml_str = String::new();
15 if let Ok(mut file) = File::open(&path) {
16 file.read_to_string(&mut toml_str).unwrap();
17 }
18 let empty = toml_str.trim().is_empty();
19 let mut root_table = toml::from_str(&toml_str).unwrap_or_else(|_| Table::new());
20 let crate_name = get_crate_name(&env.config, &root_table);
21
22 if empty {
23 fill_empty(&mut root_table, env, &crate_name);
24 }
25 fill_in(&mut root_table, env);
26
27 save_to_file(&path, env.config.make_backup, |w| {
28 w.write_all(toml::to_string(&root_table).unwrap().as_bytes())
29 });
30
31 crate_name
32}
33
34fn fill_empty(root: &mut Table, env: &Env, crate_name: &str) {
35 let package_name = nameutil::exported_crate_name(crate_name);
36
37 {
38 let package = upsert_table(root, "package");
39 set_string(package, "name", package_name);
40 set_string(package, "version", "0.0.1");
41 set_string(package, "edition", "2021");
42 }
43
44 {
45 let lib = upsert_table(root, "lib");
46 set_string(lib, "name", crate_name);
47 }
48
49 let deps = upsert_table(root, "dependencies");
50 for ext_lib in &env.config.external_libraries {
51 let ext_package = if ext_lib.crate_name == "cairo" {
52 format!("{}-sys-rs", ext_lib.crate_name)
53 } else if ext_lib.crate_name == "gdk_pixbuf" {
54 "gdk-pixbuf-sys".into()
55 } else {
56 format!("{}-sys", ext_lib.crate_name)
57 };
58 let repo_url = match ext_package.as_str() {
59 "cairo-sys-rs" | "gdk-pixbuf-sys" | "gio-sys" | "gobject-sys" | "glib-sys"
60 | "graphene-sys" | "pango-sys" | "pangocairo-sys" => {
61 "https://github.com/gtk-rs/gtk-rs-core"
62 }
63 "atk-sys" | "gdk-sys" | "gdkwayland-sys" | "gdkx11-sys" | "gtk-sys" => {
64 "https://github.com/gtk-rs/gtk3-rs"
65 }
66 "gdk4-wayland-sys" | "gdk4-x11-sys" | "gdk4-sys" | "gsk4-sys" | "gtk4-sys" => {
67 "https://github.com/gtk-rs/gtk4-rs"
68 }
69 "gstreamer-sys"
70 | "gstreamer-app-sys"
71 | "gstreamer-audio-sys"
72 | "gstreamer-base-sys"
73 | "gstreamer-check-sys"
74 | "gstreamer-controller-sys"
75 | "gstreamer-editing-services-sys"
76 | "gstreamer-gl-sys"
77 | "gstreamer-gl-egl-sys"
78 | "gstreamer-gl-wayland-sys"
79 | "gstreamer-gl-x11-sys"
80 | "gstreamer-mpegts-sys"
81 | "gstreamer-net-sys"
82 | "gstreamer-pbutils-sys"
83 | "gstreamer-player-sys"
84 | "gstreamer-rtp-sys"
85 | "gstreamer-rtsp-sys"
86 | "gstreamer-rtsp-server-sys"
87 | "gstreamer-sdp-sys"
88 | "gstreamer-tag-sys"
89 | "gstreamer-video-sys"
90 | "gstreamer-webrtc-sys"
91 | "gstreamer-allocators-sys" => "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs",
92 &_ => "ADD GIT REPOSITORY URL HERE",
93 };
94 let dep = upsert_table(deps, ext_package);
95 set_string(dep, "git", repo_url);
96 }
97}
98
99fn fill_in(root: &mut Table, env: &Env) {
100 {
101 let package = upsert_table(root, "package");
102 package
103 .entry("build")
104 .or_insert_with(|| Value::String("build.rs".into()));
105 }
107
108 {
109 let deps = upsert_table(root, "dependencies");
110 set_string(deps, "libc", "0.2");
111 }
112
113 {
114 let build_deps = upsert_table(root, "build-dependencies");
115 set_string(build_deps, "system-deps", "7");
116 }
117
118 {
119 let dev_deps = upsert_table(root, "dev-dependencies");
120 set_string(dev_deps, "shell-words", "1.0.0");
121 set_string(dev_deps, "tempfile", "3");
122 unset(dev_deps, "tempdir");
123 }
124
125 {
126 let features = upsert_table(root, "features");
127 let versions = collect_versions(env);
128 versions.keys().fold(None::<Version>, |prev, &version| {
129 let prev_array: Vec<Value> =
130 get_feature_dependencies(version, prev, &env.config.feature_dependencies)
131 .iter()
132 .map(|s| Value::String(s.clone()))
133 .collect();
134 features.insert(version.to_feature(), Value::Array(prev_array));
135 Some(version)
136 });
137 }
138
139 {
140 let meta = upsert_table(root, "package");
141 let meta = upsert_table(meta, "metadata");
142 let meta = upsert_table(meta, "system-deps");
143
144 let ns = env.namespaces.main();
145 if let Some(lib_name) = ns.package_names.first() {
146 let meta = upsert_table(meta, nameutil::lib_name_to_toml(lib_name));
147 meta.entry("name")
149 .or_insert_with(|| Value::String(lib_name.clone()));
150 meta.entry("version")
151 .or_insert_with(|| Value::String(env.config.min_cfg_version.to_string()));
152
153 unset(meta, "feature-versions");
155
156 collect_versions(env)
157 .iter()
158 .filter(|(&v, _)| v > env.config.min_cfg_version)
159 .for_each(|(v, lib_version)| {
160 let version_section = upsert_table(meta, v.to_feature());
161 version_section
163 .entry("version")
164 .or_insert_with(|| Value::String(lib_version.to_string()));
165 });
166 }
167 }
168
169 {
170 let docs_rs_metadata = upsert_table(root, "package");
173 let docs_rs_metadata = upsert_table(docs_rs_metadata, "metadata");
174 let docs_rs_metadata = upsert_table(docs_rs_metadata, "docs");
175 let docs_rs_metadata = upsert_table(docs_rs_metadata, "rs");
176
177 docs_rs_metadata.entry("rustc-args").or_insert_with(|| {
179 Value::Array(vec![
180 Value::String("--cfg".to_string()),
181 Value::String("docsrs".to_string()),
182 ])
183 });
184 docs_rs_metadata.entry("rustdoc-args").or_insert_with(|| {
185 Value::Array(vec![
186 Value::String("--cfg".to_string()),
187 Value::String("docsrs".to_string()),
188 Value::String("--generate-link-to-definition".to_string()),
189 ])
190 });
191
192 if let toml::map::Entry::Vacant(_) = docs_rs_metadata.entry("features") {
194 docs_rs_metadata.insert("all-features".to_string(), Value::Boolean(true));
195 }
196 }
197}
198
199fn get_feature_dependencies(
200 version: Version,
201 prev_version: Option<Version>,
202 feature_dependencies: &HashMap<Version, Vec<String>>,
203) -> Vec<String> {
204 let mut vec = Vec::with_capacity(10);
205 if let Some(v) = prev_version {
206 vec.push(v.to_feature());
207 }
208 if let Some(dependencies) = feature_dependencies.get(&version) {
209 vec.extend_from_slice(dependencies);
210 }
211 vec
212}
213
214fn get_crate_name(config: &Config, root: &Table) -> String {
216 if let Some(Value::Table(lib)) = root.get("lib") {
217 if let Some(Value::String(lib_name)) = lib.get("name") {
218 return lib_name.clone();
220 }
221 }
222 if let Some(Value::Table(package)) = root.get("package") {
223 if let Some(Value::String(package_name)) = package.get("name") {
224 return nameutil::crate_name(package_name);
225 }
226 }
227 format!("{}_sys", nameutil::crate_name(&config.library_name))
228}
229
230fn set_string<S: Into<String>>(table: &mut Table, name: &str, new_value: S) {
231 table.insert(name.into(), Value::String(new_value.into()));
232}
233
234fn unset(table: &mut Table, name: &str) {
235 table.remove(name);
236}
237
238fn upsert_table<S: Into<String>>(parent: &mut Table, name: S) -> &mut Table {
239 if let Value::Table(table) = parent
240 .entry(name.into())
241 .or_insert_with(|| Value::Table(toml::map::Map::new()))
242 {
243 table
244 } else {
245 unreachable!()
246 }
247}