Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/fix-ios-cmd-pkg-name-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"tauri-cli": patch:bug
"@tauri-apps/cli": patch:bug
---

Fix iOS CLI usage after modifying the package name.
29 changes: 27 additions & 2 deletions crates/tauri-cli/src/helpers/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use crate::{error::ErrorExt, Error};
use std::path::Path;
use crate::{
error::{Context, ErrorExt},
Error,
};
use std::path::{Path, PathBuf};

pub fn copy_file(from: impl AsRef<Path>, to: impl AsRef<Path>) -> crate::Result<()> {
let from = from.as_ref();
Expand All @@ -28,3 +31,25 @@ pub fn copy_file(from: impl AsRef<Path>, to: impl AsRef<Path>) -> crate::Result<
std::fs::copy(from, to).fs_context("failed to copy file", from.to_path_buf())?;
Ok(())
}

/// Find an entry in a directory matching a glob pattern.
/// Currently does not traverse subdirectories.
// currently only used on macOS
#[allow(dead_code)]
pub fn find_in_directory(path: &Path, glob_pattern: &str) -> crate::Result<PathBuf> {
let pattern = glob::Pattern::new(glob_pattern)
.with_context(|| format!("failed to parse glob pattern {glob_pattern}"))?;
for entry in std::fs::read_dir(path)
.with_context(|| format!("failed to read directory {}", path.display()))?
{
let entry = entry.context("failed to read directory entry")?;
if pattern.matches_path(&entry.path()) {
return Ok(entry.path());
}
}
crate::error::bail!(
"No file found in {} matching {}",
path.display(),
glob_pattern
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ pub fn command(options: Options) -> Result<()> {
config.app(),
config.project_dir(),
MobileTarget::Android,
std::env::var("CI").is_ok(),
)?;

if !cli_options.config.is_empty() {
Expand Down
1 change: 1 addition & 0 deletions crates/tauri-cli/src/mobile/android/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
config.app(),
config.project_dir(),
MobileTarget::Android,
options.ci,
)?;

let mut env = env(options.ci)?;
Expand Down
1 change: 1 addition & 0 deletions crates/tauri-cli/src/mobile/android/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
config.app(),
config.project_dir(),
MobileTarget::Android,
false,
)?;
run_dev(
interface,
Expand Down
1 change: 1 addition & 0 deletions crates/tauri-cli/src/mobile/ios/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
config.app(),
config.project_dir(),
MobileTarget::Ios,
options.ci,
)?;
inject_resources(&config, tauri_config.lock().unwrap().as_ref().unwrap())?;

Expand Down
1 change: 1 addition & 0 deletions crates/tauri-cli/src/mobile/ios/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
config.app(),
config.project_dir(),
MobileTarget::Ios,
false,
)?;
inject_resources(&config, tauri_config.lock().unwrap().as_ref().unwrap())?;

Expand Down
1 change: 1 addition & 0 deletions crates/tauri-cli/src/mobile/ios/xcode_script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ pub fn command(options: Options) -> Result<()> {
config.app(),
config.project_dir(),
MobileTarget::Ios,
std::env::var("CI").is_ok(),
)?;

if !cli_options.config.is_empty() {
Expand Down
88 changes: 70 additions & 18 deletions crates/tauri-cli/src/mobile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ fn ensure_init(
app: &App,
project_dir: PathBuf,
target: Target,
noninteractive: bool,
) -> Result<()> {
if !project_dir.exists() {
crate::error::bail!(
Expand Down Expand Up @@ -529,32 +530,83 @@ fn ensure_init(
}
#[cfg(target_os = "macos")]
Target::Ios => {
let pbxproj_contents = read_to_string(
project_dir
.join(format!("{}.xcodeproj", app.name()))
.join("project.pbxproj"),
)
.fs_context(
"missing project.pbxproj file in the Xcode project directory",
project_dir
.join(format!("{}.xcodeproj", app.name()))
.join("project.pbxproj"),
)?;

if !(pbxproj_contents.contains(ios::LIB_OUTPUT_FILE_NAME)
|| pbxproj_contents.contains(&format!("lib{}.a", app.lib_name())))
{
project_outdated_reasons
.push("you have modified your [lib.name] or [package.name] in the Cargo.toml file");
let xcodeproj_path = crate::helpers::fs::find_in_directory(&project_dir, "*.xcodeproj")
.with_context(|| format!("failed to locate xcodeproj in {}", project_dir.display()))?;

let xcodeproj_name = xcodeproj_path.file_stem().unwrap().to_str().unwrap();
if xcodeproj_name != app.name() {
let rename_targets = vec![
// first rename the entitlements
(
format!("{xcodeproj_name}_iOS/{xcodeproj_name}_iOS.entitlements"),
format!("{xcodeproj_name}_iOS/{}_iOS.entitlements", app.name()),
),
// then the scheme folder
(
format!("{xcodeproj_name}_iOS"),
format!("{}_iOS", app.name()),
),
(
format!("{xcodeproj_name}.xcodeproj"),
format!("{}.xcodeproj", app.name()),
),
];
let rename_info = rename_targets
.iter()
.map(|(from, to)| format!("- {from} to {to}"))
.collect::<Vec<_>>()
.join("\n");
log::error!(
"you have modified your package name from {current_project_name} to {new_project_name}\nWe need to apply the name change to the Xcode project, renaming:\n{rename_info}",
new_project_name = app.name(),
current_project_name = xcodeproj_name,
);
if noninteractive {
project_outdated_reasons
.push("you have modified your [lib.name] or [package.name] in the Cargo.toml file");
} else {
let confirm = crate::helpers::prompts::confirm(
"Do you want to apply the name change to the Xcode project?",
Some(true),
)
.unwrap_or_default();
if confirm {
for (from, to) in rename_targets {
std::fs::rename(project_dir.join(&from), project_dir.join(&to))
.with_context(|| format!("failed to rename {from} to {to}"))?;
}

// update scheme name in pbxproj
// identifier / product name are synchronized by the dev/build commands
let pbxproj_path =
project_dir.join(format!("{}.xcodeproj/project.pbxproj", app.name()));
let pbxproj_contents = std::fs::read_to_string(&pbxproj_path)
.with_context(|| format!("failed to read {}", pbxproj_path.display()))?;
std::fs::write(
&pbxproj_path,
pbxproj_contents.replace(
&format!("{xcodeproj_name}_iOS"),
&format!("{}_iOS", app.name()),
),
)
.with_context(|| format!("failed to write {}", pbxproj_path.display()))?;
} else {
project_outdated_reasons
.push("you have modified your [lib.name] or [package.name] in the Cargo.toml file");
}
}
}

// note: pbxproj is synchronied by the dev/build commands
}
}

if !project_outdated_reasons.is_empty() {
let reason = project_outdated_reasons.join(" and ");
crate::error::bail!(
"{} project directory is outdated because {reason}. Please run `tauri {} init` and try again.",
"{} project directory is outdated because {reason}. Please delete {}, run `tauri {} init` and try again.",
target.ide_name(),
project_dir.display(),
target.command_name(),
)
}
Expand Down
Loading