concinnity_dev/command/
new.rs1use std::path::{Path, PathBuf};
4
5use concinnity_cook::authoring::world::WORLD_JSONL;
6use concinnity_cook::build_from_path;
7use concinnity_host::store::paths::StateTree;
8
9const INIT_WORLD_JSONL: &str = r#"{"name":"hello_world","type":"TextLabel","args":{"content":"Hello, world!","centered":true}}
17"#;
18
19pub fn new(path: &str) -> std::io::Result<()> {
21 if let Some(world) = existing_world(Path::new(path)) {
24 return Err(std::io::Error::new(
25 std::io::ErrorKind::AlreadyExists,
26 format!("'{}' already contains a {}", path, world.display()),
27 ));
28 }
29 std::fs::create_dir_all(path)?;
30 println!("Created directory '{}'", path);
31 init_in_dir(path)
32}
33
34pub fn init() -> std::io::Result<()> {
36 init_in_dir(".")
37}
38
39fn init_in_dir(dir: &str) -> std::io::Result<()> {
41 let dir = Path::new(dir);
42 if let Some(world) = existing_world(dir) {
43 println!("{} already exists, skipping init", world.display());
44 return Ok(());
45 }
46
47 let world_path = worlds_dir(dir).join(WORLD_JSONL);
48 std::fs::create_dir_all(world_path.parent().expect("the world has a directory"))?;
49 std::fs::write(&world_path, INIT_WORLD_JSONL)?;
50 println!("Created {}", world_path.display());
51
52 let world_path_str = world_path.to_str().unwrap_or(WORLD_JSONL);
53 build_from_path(
54 &crate::project::require()?,
55 world_path_str,
56 crate::cook_platform(),
57 )
58}
59
60fn existing_world(dir: &Path) -> Option<PathBuf> {
63 [worlds_dir(dir).join(WORLD_JSONL), dir.join(WORLD_JSONL)]
64 .into_iter()
65 .find(|p| p.exists())
66}
67
68fn worlds_dir(dir: &Path) -> PathBuf {
70 StateTree::at(dir).worlds_dir()
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
81 fn new_refuses_a_directory_that_already_has_a_world() {
82 let dir = tempfile::tempdir().unwrap();
83 let world = worlds_dir(dir.path()).join(WORLD_JSONL);
84 std::fs::create_dir_all(world.parent().unwrap()).unwrap();
85 std::fs::write(&world, "").unwrap();
86
87 let err = new(dir.path().to_str().unwrap()).unwrap_err();
88 assert_eq!(err.kind(), std::io::ErrorKind::AlreadyExists);
89 assert!(err.to_string().contains(WORLD_JSONL), "got: {err}");
90 }
91
92 #[test]
95 fn new_refuses_a_directory_holding_only_a_legacy_world() {
96 let dir = tempfile::tempdir().unwrap();
97 std::fs::write(dir.path().join(WORLD_JSONL), "").unwrap();
98
99 let err = new(dir.path().to_str().unwrap()).unwrap_err();
100 assert_eq!(err.kind(), std::io::ErrorKind::AlreadyExists);
101 }
102
103 #[test]
104 fn init_in_dir_skips_when_a_world_exists() {
105 let dir = tempfile::tempdir().unwrap();
106 let world = worlds_dir(dir.path()).join(WORLD_JSONL);
107 std::fs::create_dir_all(world.parent().unwrap()).unwrap();
108 std::fs::write(
109 &world,
110 "{\"name\":\"keep\",\"type\":\"Logger\",\"args\":{}}\n",
111 )
112 .unwrap();
113
114 init_in_dir(dir.path().to_str().unwrap()).unwrap();
115 let content = std::fs::read_to_string(&world).unwrap();
117 assert!(content.contains("\"keep\""), "got: {content}");
118 }
119
120 #[test]
121 fn init_in_dir_skips_a_legacy_world_at_the_project_root() {
122 let dir = tempfile::tempdir().unwrap();
123 let world = dir.path().join(WORLD_JSONL);
124 std::fs::write(
125 &world,
126 "{\"name\":\"keep\",\"type\":\"Logger\",\"args\":{}}\n",
127 )
128 .unwrap();
129
130 init_in_dir(dir.path().to_str().unwrap()).unwrap();
131 assert!(
132 !worlds_dir(dir.path()).exists(),
133 "a legacy world is left in place rather than duplicated into worlds/"
134 );
135 }
136}