Skip to main content

ferro_cli/commands/
storage_link.rs

1//! The `storage:link` command creates a symbolic link from public/storage to storage/app/public.
2
3use std::fs;
4use std::path::Path;
5
6/// Run the storage:link command.
7pub fn run(relative: bool) {
8    let current_dir = std::env::current_dir().expect("Failed to get current directory");
9
10    // Define source and target paths
11    let storage_path = current_dir.join("storage").join("app").join("public");
12    let public_path = current_dir.join("public").join("storage");
13
14    // Ensure source directory exists
15    if !storage_path.exists() {
16        println!("Creating storage/app/public directory...");
17        if let Err(e) = fs::create_dir_all(&storage_path) {
18            eprintln!("❌ Failed to create storage directory: {e}");
19            std::process::exit(1);
20        }
21    }
22
23    // Check if link already exists
24    if public_path.exists() {
25        if public_path.is_symlink() {
26            println!("✓ Symbolic link already exists at public/storage");
27            return;
28        } else {
29            eprintln!("❌ public/storage already exists and is not a symbolic link");
30            eprintln!("   Remove it manually before running this command");
31            std::process::exit(1);
32        }
33    }
34
35    // Ensure public directory exists
36    let public_dir = current_dir.join("public");
37    if !public_dir.exists() {
38        println!("Creating public directory...");
39        if let Err(e) = fs::create_dir_all(&public_dir) {
40            eprintln!("❌ Failed to create public directory: {e}");
41            std::process::exit(1);
42        }
43    }
44
45    // Create the symbolic link
46    let target = if relative {
47        // Relative path from public/storage to storage/app/public
48        Path::new("..").join("storage").join("app").join("public")
49    } else {
50        storage_path.clone()
51    };
52
53    #[cfg(unix)]
54    {
55        if let Err(e) = std::os::unix::fs::symlink(&target, &public_path) {
56            eprintln!("❌ Failed to create symbolic link: {e}");
57            std::process::exit(1);
58        }
59    }
60
61    #[cfg(windows)]
62    {
63        // On Windows, creating symlinks requires admin privileges or developer mode
64        if let Err(e) = std::os::windows::fs::symlink_dir(&target, &public_path) {
65            eprintln!("❌ Failed to create symbolic link: {}", e);
66            eprintln!("   On Windows, you may need to run as Administrator");
67            eprintln!("   or enable Developer Mode in Windows Settings");
68            std::process::exit(1);
69        }
70    }
71
72    println!("✓ Created symbolic link: public/storage -> storage/app/public");
73    println!();
74    println!("Your application can now serve files from the storage directory.");
75    println!("Store files in storage/app/public and access them via /storage URL prefix.");
76}