mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-11-24 12:14:05 +03:00
feat(cli): add migration from 2.0.0-beta to 2.0.0-rc (#10395)
* refactor(cli): check tauri version on migration * rc migration * license headers * fix tests * add path * update schema
This commit is contained in:
parent
426d14bb41
commit
d5511c3117
6
.changes/rc-migration.md
Normal file
6
.changes/rc-migration.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"tauri-cli": patch:feat
|
||||||
|
"@tauri-apps/cli": patch:feat
|
||||||
|
---
|
||||||
|
|
||||||
|
Added migration from `2.0.0-beta` to `2.0.0-rc`.
|
@ -2551,7 +2551,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"changelog": {
|
"changelog": {
|
||||||
"description": "Path of the uncompressed Changelog file, to be stored at /usr/share/doc/package-name/changelog.gz. See\n https://www.debian.org/doc/debian-policy/ch-docs.html#changelog-files-and-release-notes",
|
"description": "Path of the uncompressed Changelog file, to be stored at /usr/share/doc/package-name/changelog.gz. See\n <https://www.debian.org/doc/debian-policy/ch-docs.html#changelog-files-and-release-notes>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
@ -2565,28 +2565,28 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"preInstallScript": {
|
"preInstallScript": {
|
||||||
"description": "Path to script that will be executed before the package is unpacked. See\n https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html",
|
"description": "Path to script that will be executed before the package is unpacked. See\n <https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"postInstallScript": {
|
"postInstallScript": {
|
||||||
"description": "Path to script that will be executed after the package is unpacked. See\n https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html",
|
"description": "Path to script that will be executed after the package is unpacked. See\n <https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"preRemoveScript": {
|
"preRemoveScript": {
|
||||||
"description": "Path to script that will be executed before the package is removed. See\n https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html",
|
"description": "Path to script that will be executed before the package is removed. See\n <https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"postRemoveScript": {
|
"postRemoveScript": {
|
||||||
"description": "Path to script that will be executed after the package is removed. See\n https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html",
|
"description": "Path to script that will be executed after the package is removed. See\n <https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
@ -2667,28 +2667,28 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"preInstallScript": {
|
"preInstallScript": {
|
||||||
"description": "Path to script that will be executed before the package is unpacked. See\n http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html",
|
"description": "Path to script that will be executed before the package is unpacked. See\n <http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"postInstallScript": {
|
"postInstallScript": {
|
||||||
"description": "Path to script that will be executed after the package is unpacked. See\n http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html",
|
"description": "Path to script that will be executed after the package is unpacked. See\n <http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"preRemoveScript": {
|
"preRemoveScript": {
|
||||||
"description": "Path to script that will be executed before the package is removed. See\n http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html",
|
"description": "Path to script that will be executed before the package is removed. See\n <http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"postRemoveScript": {
|
"postRemoveScript": {
|
||||||
"description": "Path to script that will be executed after the package is removed. See\n http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html",
|
"description": "Path to script that will be executed after the package is removed. See\n <http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
|
1
tooling/cli/Cargo.lock
generated
1
tooling/cli/Cargo.lock
generated
@ -5181,6 +5181,7 @@ dependencies = [
|
|||||||
"toml_edit 0.22.6",
|
"toml_edit 0.22.6",
|
||||||
"ureq",
|
"ureq",
|
||||||
"url",
|
"url",
|
||||||
|
"walkdir",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -98,6 +98,7 @@ oxc_allocator = "0.16"
|
|||||||
oxc_ast = "0.16"
|
oxc_ast = "0.16"
|
||||||
magic_string = "0.3"
|
magic_string = "0.3"
|
||||||
phf = { version = "0.11", features = ["macros"] }
|
phf = { version = "0.11", features = ["macros"] }
|
||||||
|
walkdir = "2"
|
||||||
|
|
||||||
[target."cfg(windows)".dependencies.windows-sys]
|
[target."cfg(windows)".dependencies.windows-sys]
|
||||||
version = "0.52"
|
version = "0.52"
|
||||||
|
@ -2551,7 +2551,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"changelog": {
|
"changelog": {
|
||||||
"description": "Path of the uncompressed Changelog file, to be stored at /usr/share/doc/package-name/changelog.gz. See\n https://www.debian.org/doc/debian-policy/ch-docs.html#changelog-files-and-release-notes",
|
"description": "Path of the uncompressed Changelog file, to be stored at /usr/share/doc/package-name/changelog.gz. See\n <https://www.debian.org/doc/debian-policy/ch-docs.html#changelog-files-and-release-notes>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
@ -2565,28 +2565,28 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"preInstallScript": {
|
"preInstallScript": {
|
||||||
"description": "Path to script that will be executed before the package is unpacked. See\n https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html",
|
"description": "Path to script that will be executed before the package is unpacked. See\n <https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"postInstallScript": {
|
"postInstallScript": {
|
||||||
"description": "Path to script that will be executed after the package is unpacked. See\n https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html",
|
"description": "Path to script that will be executed after the package is unpacked. See\n <https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"preRemoveScript": {
|
"preRemoveScript": {
|
||||||
"description": "Path to script that will be executed before the package is removed. See\n https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html",
|
"description": "Path to script that will be executed before the package is removed. See\n <https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"postRemoveScript": {
|
"postRemoveScript": {
|
||||||
"description": "Path to script that will be executed after the package is removed. See\n https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html",
|
"description": "Path to script that will be executed after the package is removed. See\n <https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
@ -2667,28 +2667,28 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"preInstallScript": {
|
"preInstallScript": {
|
||||||
"description": "Path to script that will be executed before the package is unpacked. See\n http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html",
|
"description": "Path to script that will be executed before the package is unpacked. See\n <http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"postInstallScript": {
|
"postInstallScript": {
|
||||||
"description": "Path to script that will be executed after the package is unpacked. See\n http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html",
|
"description": "Path to script that will be executed after the package is unpacked. See\n <http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"preRemoveScript": {
|
"preRemoveScript": {
|
||||||
"description": "Path to script that will be executed before the package is removed. See\n http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html",
|
"description": "Path to script that will be executed before the package is removed. See\n <http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"postRemoveScript": {
|
"postRemoveScript": {
|
||||||
"description": "Path to script that will be executed after the package is removed. See\n http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html",
|
"description": "Path to script that will be executed after the package is removed. See\n <http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html>",
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
"null"
|
"null"
|
||||||
|
@ -146,7 +146,7 @@ pub fn command(options: Options) -> Result<()> {
|
|||||||
(None, None, None, None) => npm_name,
|
(None, None, None, None) => npm_name,
|
||||||
_ => anyhow::bail!("Only one of --tag, --rev and --branch can be specified"),
|
_ => anyhow::bail!("Only one of --tag, --rev and --branch can be specified"),
|
||||||
};
|
};
|
||||||
manager.install(&[npm_spec])?;
|
manager.install(&[npm_spec], &tauri_dir)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = acl::permission::add::command(acl::permission::add::Options {
|
let _ = acl::permission::add::command(acl::permission::add::Options {
|
||||||
|
172
tooling/cli/src/helpers/cargo_manifest.rs
Normal file
172
tooling/cli/src/helpers/cargo_manifest.rs
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fmt::Write,
|
||||||
|
fs::read_to_string,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize)]
|
||||||
|
pub struct CargoLockPackage {
|
||||||
|
pub name: String,
|
||||||
|
pub version: String,
|
||||||
|
pub source: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct CargoLock {
|
||||||
|
pub package: Vec<CargoLockPackage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize)]
|
||||||
|
pub struct CargoManifestDependencyPackage {
|
||||||
|
pub version: Option<String>,
|
||||||
|
pub git: Option<String>,
|
||||||
|
pub branch: Option<String>,
|
||||||
|
pub rev: Option<String>,
|
||||||
|
pub path: Option<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum CargoManifestDependency {
|
||||||
|
Version(String),
|
||||||
|
Package(CargoManifestDependencyPackage),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct CargoManifestPackage {
|
||||||
|
pub version: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct CargoManifest {
|
||||||
|
pub package: CargoManifestPackage,
|
||||||
|
pub dependencies: HashMap<String, CargoManifestDependency>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CrateVersion {
|
||||||
|
pub version: String,
|
||||||
|
pub found_crate_versions: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn crate_version(
|
||||||
|
tauri_dir: &Path,
|
||||||
|
manifest: Option<&CargoManifest>,
|
||||||
|
lock: Option<&CargoLock>,
|
||||||
|
name: &str,
|
||||||
|
) -> CrateVersion {
|
||||||
|
let crate_lock_packages: Vec<CargoLockPackage> = lock
|
||||||
|
.as_ref()
|
||||||
|
.map(|lock| {
|
||||||
|
lock
|
||||||
|
.package
|
||||||
|
.iter()
|
||||||
|
.filter(|p| p.name == name)
|
||||||
|
.cloned()
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
let (crate_version_string, found_crate_versions) =
|
||||||
|
match (&manifest, &lock, crate_lock_packages.len()) {
|
||||||
|
(Some(_manifest), Some(_lock), 1) => {
|
||||||
|
let crate_lock_package = crate_lock_packages.first().unwrap();
|
||||||
|
let version_string = if let Some(s) = &crate_lock_package.source {
|
||||||
|
if s.starts_with("git") {
|
||||||
|
format!("{} ({})", s, crate_lock_package.version)
|
||||||
|
} else {
|
||||||
|
crate_lock_package.version.clone()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
crate_lock_package.version.clone()
|
||||||
|
};
|
||||||
|
(version_string, vec![crate_lock_package.version.clone()])
|
||||||
|
}
|
||||||
|
(None, Some(_lock), 1) => {
|
||||||
|
let crate_lock_package = crate_lock_packages.first().unwrap();
|
||||||
|
let version_string = if let Some(s) = &crate_lock_package.source {
|
||||||
|
if s.starts_with("git") {
|
||||||
|
format!("{} ({})", s, crate_lock_package.version)
|
||||||
|
} else {
|
||||||
|
crate_lock_package.version.clone()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
crate_lock_package.version.clone()
|
||||||
|
};
|
||||||
|
(
|
||||||
|
format!("{version_string} (no manifest)"),
|
||||||
|
vec![crate_lock_package.version.clone()],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let mut found_crate_versions = Vec::new();
|
||||||
|
let mut is_git = false;
|
||||||
|
let manifest_version = match manifest.and_then(|m| m.dependencies.get(name).cloned()) {
|
||||||
|
Some(tauri) => match tauri {
|
||||||
|
CargoManifestDependency::Version(v) => {
|
||||||
|
found_crate_versions.push(v.clone());
|
||||||
|
v
|
||||||
|
}
|
||||||
|
CargoManifestDependency::Package(p) => {
|
||||||
|
if let Some(v) = p.version {
|
||||||
|
found_crate_versions.push(v.clone());
|
||||||
|
v
|
||||||
|
} else if let Some(p) = p.path {
|
||||||
|
let manifest_path = tauri_dir.join(&p).join("Cargo.toml");
|
||||||
|
let v = match read_to_string(manifest_path)
|
||||||
|
.map_err(|_| ())
|
||||||
|
.and_then(|m| toml::from_str::<CargoManifest>(&m).map_err(|_| ()))
|
||||||
|
{
|
||||||
|
Ok(manifest) => manifest.package.version,
|
||||||
|
Err(_) => "unknown version".to_string(),
|
||||||
|
};
|
||||||
|
format!("path:{p:?} [{v}]")
|
||||||
|
} else if let Some(g) = p.git {
|
||||||
|
is_git = true;
|
||||||
|
let mut v = format!("git:{g}");
|
||||||
|
if let Some(branch) = p.branch {
|
||||||
|
let _ = write!(v, "&branch={branch}");
|
||||||
|
} else if let Some(rev) = p.rev {
|
||||||
|
let _ = write!(v, "#{rev}");
|
||||||
|
}
|
||||||
|
v
|
||||||
|
} else {
|
||||||
|
"unknown manifest".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => "no manifest".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let lock_version = match (lock, crate_lock_packages.is_empty()) {
|
||||||
|
(Some(_lock), false) => crate_lock_packages
|
||||||
|
.iter()
|
||||||
|
.map(|p| p.version.clone())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", "),
|
||||||
|
(Some(_lock), true) => "unknown lockfile".to_string(),
|
||||||
|
_ => "no lockfile".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
format!(
|
||||||
|
"{} {}({})",
|
||||||
|
manifest_version,
|
||||||
|
if is_git { "(git manifest)" } else { "" },
|
||||||
|
lock_version
|
||||||
|
),
|
||||||
|
found_crate_versions,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CrateVersion {
|
||||||
|
found_crate_versions,
|
||||||
|
version: crate_version_string,
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
pub mod app_paths;
|
pub mod app_paths;
|
||||||
pub mod cargo;
|
pub mod cargo;
|
||||||
|
pub mod cargo_manifest;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod flock;
|
pub mod flock;
|
||||||
pub mod framework;
|
pub mod framework;
|
||||||
|
@ -81,7 +81,7 @@ impl PackageManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install(&self, dependencies: &[String]) -> crate::Result<()> {
|
pub fn install<P: AsRef<Path>>(&self, dependencies: &[String], app_dir: P) -> crate::Result<()> {
|
||||||
let dependencies_str = if dependencies.len() > 1 {
|
let dependencies_str = if dependencies.len() > 1 {
|
||||||
"dependencies"
|
"dependencies"
|
||||||
} else {
|
} else {
|
||||||
@ -100,6 +100,7 @@ impl PackageManager {
|
|||||||
.cross_command()
|
.cross_command()
|
||||||
.arg("add")
|
.arg("add")
|
||||||
.args(dependencies)
|
.args(dependencies)
|
||||||
|
.current_dir(app_dir)
|
||||||
.status()
|
.status()
|
||||||
.with_context(|| format!("failed to run {self}"))?;
|
.with_context(|| format!("failed to run {self}"))?;
|
||||||
|
|
||||||
@ -109,4 +110,71 @@ impl PackageManager {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn current_package_version<P: AsRef<Path>>(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
app_dir: P,
|
||||||
|
) -> crate::Result<Option<String>> {
|
||||||
|
let (output, regex) = match self {
|
||||||
|
PackageManager::Yarn => (
|
||||||
|
cross_command("yarn")
|
||||||
|
.args(["list", "--pattern"])
|
||||||
|
.arg(name)
|
||||||
|
.args(["--depth", "0"])
|
||||||
|
.current_dir(app_dir)
|
||||||
|
.output()?,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PackageManager::YarnBerry => (
|
||||||
|
cross_command("yarn")
|
||||||
|
.arg("info")
|
||||||
|
.arg(name)
|
||||||
|
.arg("--json")
|
||||||
|
.current_dir(app_dir)
|
||||||
|
.output()?,
|
||||||
|
Some(regex::Regex::new("\"Version\":\"([\\da-zA-Z\\-\\.]+)\"").unwrap()),
|
||||||
|
),
|
||||||
|
PackageManager::Npm => (
|
||||||
|
cross_command("npm")
|
||||||
|
.arg("list")
|
||||||
|
.arg(name)
|
||||||
|
.args(["version", "--depth", "0"])
|
||||||
|
.current_dir(app_dir)
|
||||||
|
.output()?,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
PackageManager::Pnpm => (
|
||||||
|
cross_command("pnpm")
|
||||||
|
.arg("list")
|
||||||
|
.arg(name)
|
||||||
|
.args(["--parseable", "--depth", "0"])
|
||||||
|
.current_dir(app_dir)
|
||||||
|
.output()?,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
// Bun doesn't support `list` command
|
||||||
|
PackageManager::Bun => (
|
||||||
|
cross_command("npm")
|
||||||
|
.arg("list")
|
||||||
|
.arg(name)
|
||||||
|
.args(["version", "--depth", "0"])
|
||||||
|
.current_dir(app_dir)
|
||||||
|
.output()?,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
if output.status.success() {
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
let regex = regex.unwrap_or_else(|| regex::Regex::new("@(\\d[\\da-zA-Z\\-\\.]+)").unwrap());
|
||||||
|
Ok(
|
||||||
|
regex
|
||||||
|
.captures_iter(&stdout)
|
||||||
|
.last()
|
||||||
|
.and_then(|cap| cap.get(1).map(|v| v.as_str().to_string())),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use super::SectionItem;
|
|||||||
use super::{env_nodejs::manager_version, VersionMetadata};
|
use super::{env_nodejs::manager_version, VersionMetadata};
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::helpers::{cross_command, npm::PackageManager};
|
use crate::helpers::{cross_command, npm::PackageManager};
|
||||||
|
|
||||||
@ -87,73 +87,6 @@ fn npm_latest_version(pm: &PackageManager, name: &str) -> crate::Result<Option<S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn npm_package_version<P: AsRef<Path>>(
|
|
||||||
pm: &PackageManager,
|
|
||||||
name: &str,
|
|
||||||
app_dir: P,
|
|
||||||
) -> crate::Result<Option<String>> {
|
|
||||||
let (output, regex) = match pm {
|
|
||||||
PackageManager::Yarn => (
|
|
||||||
cross_command("yarn")
|
|
||||||
.args(["list", "--pattern"])
|
|
||||||
.arg(name)
|
|
||||||
.args(["--depth", "0"])
|
|
||||||
.current_dir(app_dir)
|
|
||||||
.output()?,
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
PackageManager::YarnBerry => (
|
|
||||||
cross_command("yarn")
|
|
||||||
.arg("info")
|
|
||||||
.arg(name)
|
|
||||||
.arg("--json")
|
|
||||||
.current_dir(app_dir)
|
|
||||||
.output()?,
|
|
||||||
Some(regex::Regex::new("\"Version\":\"([\\da-zA-Z\\-\\.]+)\"").unwrap()),
|
|
||||||
),
|
|
||||||
PackageManager::Npm => (
|
|
||||||
cross_command("npm")
|
|
||||||
.arg("list")
|
|
||||||
.arg(name)
|
|
||||||
.args(["version", "--depth", "0"])
|
|
||||||
.current_dir(app_dir)
|
|
||||||
.output()?,
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
PackageManager::Pnpm => (
|
|
||||||
cross_command("pnpm")
|
|
||||||
.arg("list")
|
|
||||||
.arg(name)
|
|
||||||
.args(["--parseable", "--depth", "0"])
|
|
||||||
.current_dir(app_dir)
|
|
||||||
.output()?,
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
// Bun doesn't support `list` command
|
|
||||||
PackageManager::Bun => (
|
|
||||||
cross_command("npm")
|
|
||||||
.arg("list")
|
|
||||||
.arg(name)
|
|
||||||
.args(["version", "--depth", "0"])
|
|
||||||
.current_dir(app_dir)
|
|
||||||
.output()?,
|
|
||||||
None,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
if output.status.success() {
|
|
||||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
||||||
let regex = regex.unwrap_or_else(|| regex::Regex::new("@(\\d[\\da-zA-Z\\-\\.]+)").unwrap());
|
|
||||||
Ok(
|
|
||||||
regex
|
|
||||||
.captures_iter(&stdout)
|
|
||||||
.last()
|
|
||||||
.and_then(|cap| cap.get(1).map(|v| v.as_str().to_string())),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_package_manager<T: AsRef<str>>(app_dir_entries: &[T]) -> PackageManager {
|
fn get_package_manager<T: AsRef<str>>(app_dir_entries: &[T]) -> PackageManager {
|
||||||
let mut use_npm = false;
|
let mut use_npm = false;
|
||||||
let mut use_pnpm = false;
|
let mut use_pnpm = false;
|
||||||
@ -244,7 +177,8 @@ pub fn items(app_dir: Option<&PathBuf>, metadata: &VersionMetadata) -> Vec<Secti
|
|||||||
let app_dir = app_dir.clone();
|
let app_dir = app_dir.clone();
|
||||||
let item = SectionItem::new().action(move || {
|
let item = SectionItem::new().action(move || {
|
||||||
let version = version.clone().unwrap_or_else(|| {
|
let version = version.clone().unwrap_or_else(|| {
|
||||||
npm_package_version(&package_manager, package, &app_dir)
|
package_manager
|
||||||
|
.current_package_version(package, &app_dir)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
});
|
});
|
||||||
|
@ -3,53 +3,14 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use super::{ActionResult, SectionItem};
|
use super::{ActionResult, SectionItem};
|
||||||
use crate::interface::rust::get_workspace_dir;
|
use crate::{
|
||||||
|
helpers::cargo_manifest::{crate_version, CargoLock, CargoManifest},
|
||||||
|
interface::rust::get_workspace_dir,
|
||||||
|
};
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use serde::Deserialize;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt::Write;
|
|
||||||
use std::fs::read_to_string;
|
use std::fs::read_to_string;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
#[derive(Clone, Deserialize)]
|
|
||||||
struct CargoLockPackage {
|
|
||||||
name: String,
|
|
||||||
version: String,
|
|
||||||
source: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct CargoLock {
|
|
||||||
package: Vec<CargoLockPackage>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Deserialize)]
|
|
||||||
struct CargoManifestDependencyPackage {
|
|
||||||
version: Option<String>,
|
|
||||||
git: Option<String>,
|
|
||||||
branch: Option<String>,
|
|
||||||
rev: Option<String>,
|
|
||||||
path: Option<PathBuf>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Deserialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
enum CargoManifestDependency {
|
|
||||||
Version(String),
|
|
||||||
Package(CargoManifestDependencyPackage),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct CargoManifestPackage {
|
|
||||||
version: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct CargoManifest {
|
|
||||||
package: CargoManifestPackage,
|
|
||||||
dependencies: HashMap<String, CargoManifestDependency>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn crate_latest_version(name: &str) -> Option<String> {
|
fn crate_latest_version(name: &str) -> Option<String> {
|
||||||
let url = format!("https://docs.rs/crate/{name}/");
|
let url = format!("https://docs.rs/crate/{name}/");
|
||||||
match ureq::get(&url).call() {
|
match ureq::get(&url).call() {
|
||||||
@ -61,138 +22,6 @@ fn crate_latest_version(name: &str) -> Option<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn crate_version(
|
|
||||||
tauri_dir: &Path,
|
|
||||||
manifest: Option<&CargoManifest>,
|
|
||||||
lock: Option<&CargoLock>,
|
|
||||||
name: &str,
|
|
||||||
) -> (String, Option<String>) {
|
|
||||||
let crate_lock_packages: Vec<CargoLockPackage> = lock
|
|
||||||
.as_ref()
|
|
||||||
.map(|lock| {
|
|
||||||
lock
|
|
||||||
.package
|
|
||||||
.iter()
|
|
||||||
.filter(|p| p.name == name)
|
|
||||||
.cloned()
|
|
||||||
.collect()
|
|
||||||
})
|
|
||||||
.unwrap_or_default();
|
|
||||||
let (crate_version_string, found_crate_versions) =
|
|
||||||
match (&manifest, &lock, crate_lock_packages.len()) {
|
|
||||||
(Some(_manifest), Some(_lock), 1) => {
|
|
||||||
let crate_lock_package = crate_lock_packages.first().unwrap();
|
|
||||||
let version_string = if let Some(s) = &crate_lock_package.source {
|
|
||||||
if s.starts_with("git") {
|
|
||||||
format!("{} ({})", s, crate_lock_package.version)
|
|
||||||
} else {
|
|
||||||
crate_lock_package.version.clone()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
crate_lock_package.version.clone()
|
|
||||||
};
|
|
||||||
(version_string, vec![crate_lock_package.version.clone()])
|
|
||||||
}
|
|
||||||
(None, Some(_lock), 1) => {
|
|
||||||
let crate_lock_package = crate_lock_packages.first().unwrap();
|
|
||||||
let version_string = if let Some(s) = &crate_lock_package.source {
|
|
||||||
if s.starts_with("git") {
|
|
||||||
format!("{} ({})", s, crate_lock_package.version)
|
|
||||||
} else {
|
|
||||||
crate_lock_package.version.clone()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
crate_lock_package.version.clone()
|
|
||||||
};
|
|
||||||
(
|
|
||||||
format!("{version_string} (no manifest)"),
|
|
||||||
vec![crate_lock_package.version.clone()],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let mut found_crate_versions = Vec::new();
|
|
||||||
let mut is_git = false;
|
|
||||||
let manifest_version = match manifest.and_then(|m| m.dependencies.get(name).cloned()) {
|
|
||||||
Some(tauri) => match tauri {
|
|
||||||
CargoManifestDependency::Version(v) => {
|
|
||||||
found_crate_versions.push(v.clone());
|
|
||||||
v
|
|
||||||
}
|
|
||||||
CargoManifestDependency::Package(p) => {
|
|
||||||
if let Some(v) = p.version {
|
|
||||||
found_crate_versions.push(v.clone());
|
|
||||||
v
|
|
||||||
} else if let Some(p) = p.path {
|
|
||||||
let manifest_path = tauri_dir.join(&p).join("Cargo.toml");
|
|
||||||
let v = match read_to_string(manifest_path)
|
|
||||||
.map_err(|_| ())
|
|
||||||
.and_then(|m| toml::from_str::<CargoManifest>(&m).map_err(|_| ()))
|
|
||||||
{
|
|
||||||
Ok(manifest) => manifest.package.version,
|
|
||||||
Err(_) => "unknown version".to_string(),
|
|
||||||
};
|
|
||||||
format!("path:{p:?} [{v}]")
|
|
||||||
} else if let Some(g) = p.git {
|
|
||||||
is_git = true;
|
|
||||||
let mut v = format!("git:{g}");
|
|
||||||
if let Some(branch) = p.branch {
|
|
||||||
let _ = write!(v, "&branch={branch}");
|
|
||||||
} else if let Some(rev) = p.rev {
|
|
||||||
let _ = write!(v, "#{rev}");
|
|
||||||
}
|
|
||||||
v
|
|
||||||
} else {
|
|
||||||
"unknown manifest".to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
None => "no manifest".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let lock_version = match (lock, crate_lock_packages.is_empty()) {
|
|
||||||
(Some(_lock), false) => crate_lock_packages
|
|
||||||
.iter()
|
|
||||||
.map(|p| p.version.clone())
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(", "),
|
|
||||||
(Some(_lock), true) => "unknown lockfile".to_string(),
|
|
||||||
_ => "no lockfile".to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
(
|
|
||||||
format!(
|
|
||||||
"{} {}({})",
|
|
||||||
manifest_version,
|
|
||||||
if is_git { "(git manifest)" } else { "" },
|
|
||||||
lock_version
|
|
||||||
),
|
|
||||||
found_crate_versions,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let crate_version = found_crate_versions
|
|
||||||
.into_iter()
|
|
||||||
.map(|v| semver::Version::parse(&v).ok())
|
|
||||||
.max();
|
|
||||||
let suffix = match (crate_version, crate_latest_version(name)) {
|
|
||||||
(Some(Some(version)), Some(target_version)) => {
|
|
||||||
let target_version = semver::Version::parse(&target_version).unwrap();
|
|
||||||
if version < target_version {
|
|
||||||
Some(format!(
|
|
||||||
" ({}, latest: {})",
|
|
||||||
"outdated".yellow(),
|
|
||||||
target_version.to_string().green()
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
(crate_version_string, suffix)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn items(app_dir: Option<&PathBuf>, tauri_dir: Option<&Path>) -> Vec<SectionItem> {
|
pub fn items(app_dir: Option<&PathBuf>, tauri_dir: Option<&Path>) -> Vec<SectionItem> {
|
||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
|
|
||||||
@ -210,13 +39,34 @@ pub fn items(app_dir: Option<&PathBuf>, tauri_dir: Option<&Path>) -> Vec<Section
|
|||||||
.and_then(|s| toml::from_str(&s).ok());
|
.and_then(|s| toml::from_str(&s).ok());
|
||||||
|
|
||||||
for dep in ["tauri", "tauri-build", "wry", "tao"] {
|
for dep in ["tauri", "tauri-build", "wry", "tao"] {
|
||||||
let (version_string, version_suffix) =
|
let version = crate_version(tauri_dir, manifest.as_ref(), lock.as_ref(), dep);
|
||||||
crate_version(tauri_dir, manifest.as_ref(), lock.as_ref(), dep);
|
let crate_version = version
|
||||||
|
.found_crate_versions
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| semver::Version::parse(&v).ok())
|
||||||
|
.max();
|
||||||
|
|
||||||
|
let version_suffix = match (crate_version, crate_latest_version(dep)) {
|
||||||
|
(Some(Some(version)), Some(target_version)) => {
|
||||||
|
let target_version = semver::Version::parse(&target_version).unwrap();
|
||||||
|
if version < target_version {
|
||||||
|
Some(format!(
|
||||||
|
" ({}, latest: {})",
|
||||||
|
"outdated".yellow(),
|
||||||
|
target_version.to_string().green()
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
let item = SectionItem::new().description(format!(
|
let item = SectionItem::new().description(format!(
|
||||||
"{} {}: {}{}",
|
"{} {}: {}{}",
|
||||||
dep,
|
dep,
|
||||||
"[RUST]".dimmed(),
|
"[RUST]".dimmed(),
|
||||||
version_string,
|
version.version,
|
||||||
version_suffix
|
version_suffix
|
||||||
.clone()
|
.clone()
|
||||||
.map(|s| format!(",{s}"))
|
.map(|s| format!(",{s}"))
|
||||||
|
@ -96,6 +96,18 @@ pub fn read_manifest(manifest_path: &Path) -> crate::Result<(Document, String)>
|
|||||||
Ok((manifest, manifest_str))
|
Ok((manifest, manifest_str))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn serialize_manifest(manifest: &Document) -> String {
|
||||||
|
manifest
|
||||||
|
.to_string()
|
||||||
|
// apply some formatting fixes
|
||||||
|
.replace(r#"" ,features =["#, r#"", features = ["#)
|
||||||
|
.replace(r#"" , features"#, r#"", features"#)
|
||||||
|
.replace("]}", "] }")
|
||||||
|
.replace("={", "= {")
|
||||||
|
.replace("=[", "= [")
|
||||||
|
.replace(r#"",""#, r#"", ""#)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn toml_array(features: &HashSet<String>) -> Array {
|
pub fn toml_array(features: &HashSet<String>) -> Array {
|
||||||
let mut f = Array::default();
|
let mut f = Array::default();
|
||||||
let mut features: Vec<String> = features.iter().map(|f| f.to_string()).collect();
|
let mut features: Vec<String> = features.iter().map(|f| f.to_string()).collect();
|
||||||
@ -301,15 +313,7 @@ pub fn rewrite_manifest(config: &Config) -> crate::Result<(Manifest, bool)> {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.features;
|
.features;
|
||||||
|
|
||||||
let new_manifest_str = manifest
|
let new_manifest_str = serialize_manifest(&manifest);
|
||||||
.to_string()
|
|
||||||
// apply some formatting fixes
|
|
||||||
.replace(r#"" ,features =["#, r#"", features = ["#)
|
|
||||||
.replace(r#"" , features"#, r#"", features"#)
|
|
||||||
.replace("]}", "] }")
|
|
||||||
.replace("={", "= {")
|
|
||||||
.replace("=[", "= [")
|
|
||||||
.replace(r#"",""#, r#"", ""#);
|
|
||||||
|
|
||||||
if persist && original_manifest_str != new_manifest_str {
|
if persist && original_manifest_str != new_manifest_str {
|
||||||
let mut manifest_file =
|
let mut manifest_file =
|
||||||
|
6
tooling/cli/src/migrate/migrations/mod.rs
Normal file
6
tooling/cli/src/migrate/migrations/mod.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
pub mod v1;
|
||||||
|
pub mod v2_rc;
|
@ -58,11 +58,34 @@ pub fn migrate(app_dir: &Path, tauri_dir: &Path) -> Result<()> {
|
|||||||
let mut new_npm_packages = Vec::new();
|
let mut new_npm_packages = Vec::new();
|
||||||
let mut new_cargo_packages = Vec::new();
|
let mut new_cargo_packages = Vec::new();
|
||||||
|
|
||||||
|
let pre = env!("CARGO_PKG_VERSION_PRE");
|
||||||
|
let npm_version = if pre.is_empty() {
|
||||||
|
format!("{}.0.0", env!("CARGO_PKG_VERSION_MAJOR"))
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
"{}.{}.{}-{}.0",
|
||||||
|
env!("CARGO_PKG_VERSION_MAJOR"),
|
||||||
|
env!("CARGO_PKG_VERSION_MINOR"),
|
||||||
|
env!("CARGO_PKG_VERSION_PATCH"),
|
||||||
|
pre.split('.').next().unwrap()
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let pm = PackageManager::from_project(app_dir)
|
let pm = PackageManager::from_project(app_dir)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.next()
|
.next()
|
||||||
.unwrap_or(PackageManager::Npm);
|
.unwrap_or(PackageManager::Npm);
|
||||||
|
|
||||||
|
for pkg in ["@tauri-apps/cli", "@tauri-apps/api"] {
|
||||||
|
let version = pm
|
||||||
|
.current_package_version(pkg, app_dir)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.unwrap_or_default();
|
||||||
|
if version.starts_with("1") {
|
||||||
|
new_npm_packages.push(format!("{pkg}@^{npm_version}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for entry in walk_builder(app_dir).build().flatten() {
|
for entry in walk_builder(app_dir).build().flatten() {
|
||||||
if entry.file_type().map(|t| t.is_file()).unwrap_or_default() {
|
if entry.file_type().map(|t| t.is_file()).unwrap_or_default() {
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
@ -86,7 +109,7 @@ pub fn migrate(app_dir: &Path, tauri_dir: &Path) -> Result<()> {
|
|||||||
new_npm_packages.sort();
|
new_npm_packages.sort();
|
||||||
new_npm_packages.dedup();
|
new_npm_packages.dedup();
|
||||||
if !new_npm_packages.is_empty() {
|
if !new_npm_packages.is_empty() {
|
||||||
pm.install(&new_npm_packages)
|
pm.install(&new_npm_packages, app_dir)
|
||||||
.context("Error installing new npm packages")?;
|
.context("Error installing new npm packages")?;
|
||||||
}
|
}
|
||||||
|
|
@ -2,14 +2,17 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use crate::{interface::rust::manifest::read_manifest, Result};
|
use crate::{
|
||||||
|
interface::rust::manifest::{read_manifest, serialize_manifest},
|
||||||
|
Result,
|
||||||
|
};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use tauri_utils_v1::config::Allowlist;
|
use tauri_utils_v1::config::Allowlist;
|
||||||
use toml_edit::{Document, Entry, Item, Table, TableLike, Value};
|
use toml_edit::{Document, Entry, Item, Table, TableLike, Value};
|
||||||
|
|
||||||
use std::{fs::File, io::Write, path::Path};
|
use std::path::Path;
|
||||||
|
|
||||||
const CRATE_TYPES: [&str; 3] = ["lib", "staticlib", "cdylib"];
|
const CRATE_TYPES: [&str; 3] = ["lib", "staticlib", "cdylib"];
|
||||||
|
|
||||||
@ -18,20 +21,8 @@ pub fn migrate(tauri_dir: &Path) -> Result<()> {
|
|||||||
let (mut manifest, _) = read_manifest(&manifest_path)?;
|
let (mut manifest, _) = read_manifest(&manifest_path)?;
|
||||||
migrate_manifest(&mut manifest)?;
|
migrate_manifest(&mut manifest)?;
|
||||||
|
|
||||||
let mut manifest_file =
|
std::fs::write(&manifest_path, serialize_manifest(&manifest))
|
||||||
File::create(&manifest_path).with_context(|| "failed to open Cargo.toml for rewrite")?;
|
.context("failed to rewrite Cargo manifest")?;
|
||||||
manifest_file.write_all(
|
|
||||||
manifest
|
|
||||||
.to_string()
|
|
||||||
// apply some formatting fixes
|
|
||||||
.replace(r#"" ,features =["#, r#"", features = ["#)
|
|
||||||
.replace(r#"" , features"#, r#"", features"#)
|
|
||||||
.replace("]}", "] }")
|
|
||||||
.replace("={", "= {")
|
|
||||||
.replace("=[", "= [")
|
|
||||||
.as_bytes(),
|
|
||||||
)?;
|
|
||||||
manifest_file.flush()?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -44,7 +35,7 @@ fn migrate_manifest(manifest: &mut Document) -> Result<()> {
|
|||||||
.entry("dependencies")
|
.entry("dependencies")
|
||||||
.or_insert(Item::Table(Table::new()))
|
.or_insert(Item::Table(Table::new()))
|
||||||
.as_table_mut()
|
.as_table_mut()
|
||||||
.expect("manifest dependencies isn't a table");
|
.context("manifest dependencies isn't a table")?;
|
||||||
|
|
||||||
migrate_dependency(dependencies, "tauri", &version, &features_to_remove());
|
migrate_dependency(dependencies, "tauri", &version, &features_to_remove());
|
||||||
|
|
||||||
@ -53,7 +44,7 @@ fn migrate_manifest(manifest: &mut Document) -> Result<()> {
|
|||||||
.entry("build-dependencies")
|
.entry("build-dependencies")
|
||||||
.or_insert(Item::Table(Table::new()))
|
.or_insert(Item::Table(Table::new()))
|
||||||
.as_table_mut()
|
.as_table_mut()
|
||||||
.expect("manifest build-dependencies isn't a table");
|
.context("manifest build-dependencies isn't a table")?;
|
||||||
|
|
||||||
migrate_dependency(build_dependencies, "tauri-build", &version, &[]);
|
migrate_dependency(build_dependencies, "tauri-build", &version, &[]);
|
||||||
|
|
36
tooling/cli/src/migrate/migrations/v1/mod.rs
Normal file
36
tooling/cli/src/migrate/migrations/v1/mod.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
helpers::app_paths::{app_dir, tauri_dir},
|
||||||
|
Result,
|
||||||
|
};
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
|
||||||
|
mod config;
|
||||||
|
mod frontend;
|
||||||
|
mod manifest;
|
||||||
|
|
||||||
|
pub fn run() -> Result<()> {
|
||||||
|
let tauri_dir = tauri_dir();
|
||||||
|
let app_dir = app_dir();
|
||||||
|
|
||||||
|
let migrated = config::migrate(&tauri_dir).context("Could not migrate config")?;
|
||||||
|
manifest::migrate(&tauri_dir).context("Could not migrate manifest")?;
|
||||||
|
frontend::migrate(app_dir, &tauri_dir)?;
|
||||||
|
|
||||||
|
// Add plugins
|
||||||
|
for plugin in migrated.plugins {
|
||||||
|
crate::add::command(crate::add::Options {
|
||||||
|
plugin: plugin.clone(),
|
||||||
|
branch: None,
|
||||||
|
tag: None,
|
||||||
|
rev: None,
|
||||||
|
})
|
||||||
|
.with_context(|| format!("Could not migrate plugin '{plugin}'"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
196
tooling/cli/src/migrate/migrations/v2_rc.rs
Normal file
196
tooling/cli/src/migrate/migrations/v2_rc.rs
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
helpers::{
|
||||||
|
app_paths::{app_dir, tauri_dir},
|
||||||
|
npm::PackageManager,
|
||||||
|
},
|
||||||
|
interface::rust::manifest::{read_manifest, serialize_manifest},
|
||||||
|
Result,
|
||||||
|
};
|
||||||
|
|
||||||
|
use std::{fs::read_to_string, path::Path};
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
use toml_edit::{Document, Item, Table, TableLike, Value};
|
||||||
|
|
||||||
|
pub fn run() -> Result<()> {
|
||||||
|
let app_dir = app_dir();
|
||||||
|
let tauri_dir = tauri_dir();
|
||||||
|
|
||||||
|
let manifest_path = tauri_dir.join("Cargo.toml");
|
||||||
|
let (mut manifest, _) = read_manifest(&manifest_path)?;
|
||||||
|
migrate_manifest(&mut manifest)?;
|
||||||
|
|
||||||
|
migrate_permissions(&tauri_dir)?;
|
||||||
|
|
||||||
|
migrate_npm_dependencies(app_dir)?;
|
||||||
|
|
||||||
|
std::fs::write(&manifest_path, serialize_manifest(&manifest))
|
||||||
|
.context("failed to rewrite Cargo manifest")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn migrate_npm_dependencies(app_dir: &Path) -> Result<()> {
|
||||||
|
let pm = PackageManager::from_project(app_dir)
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
.unwrap_or(PackageManager::Npm);
|
||||||
|
|
||||||
|
let mut install_deps = Vec::new();
|
||||||
|
for pkg in [
|
||||||
|
"@tauri-apps/cli",
|
||||||
|
"@tauri-apps/api",
|
||||||
|
"@tauri-apps/plugin-authenticator",
|
||||||
|
"@tauri-apps/plugin-autostart",
|
||||||
|
"@tauri-apps/plugin-barcode-scanner",
|
||||||
|
"@tauri-apps/plugin-biometric",
|
||||||
|
"@tauri-apps/plugin-cli",
|
||||||
|
"@tauri-apps/plugin-clipboard-manager",
|
||||||
|
"@tauri-apps/plugin-deep-link",
|
||||||
|
"@tauri-apps/plugin-dialog",
|
||||||
|
"@tauri-apps/plugin-fs",
|
||||||
|
"@tauri-apps/plugin-global-shortcut",
|
||||||
|
"@tauri-apps/plugin-http",
|
||||||
|
"@tauri-apps/plugin-log",
|
||||||
|
"@tauri-apps/plugin-nfc",
|
||||||
|
"@tauri-apps/plugin-notification",
|
||||||
|
"@tauri-apps/plugin-os",
|
||||||
|
"@tauri-apps/plugin-positioner",
|
||||||
|
"@tauri-apps/plugin-process",
|
||||||
|
"@tauri-apps/plugin-shell",
|
||||||
|
"@tauri-apps/plugin-sql",
|
||||||
|
"@tauri-apps/plugin-store",
|
||||||
|
"@tauri-apps/plugin-stronghold",
|
||||||
|
"@tauri-apps/plugin-updater",
|
||||||
|
"@tauri-apps/plugin-upload",
|
||||||
|
"@tauri-apps/plugin-websocket",
|
||||||
|
"@tauri-apps/plugin-window-state",
|
||||||
|
] {
|
||||||
|
let version = pm
|
||||||
|
.current_package_version(pkg, app_dir)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.unwrap_or_default();
|
||||||
|
if version.starts_with("1") {
|
||||||
|
install_deps.push(format!("{pkg}@^2.0.0-rc.0"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !install_deps.is_empty() {
|
||||||
|
pm.install(&install_deps, app_dir)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn migrate_permissions(tauri_dir: &Path) -> Result<()> {
|
||||||
|
let core_plugins = [
|
||||||
|
"app",
|
||||||
|
"event",
|
||||||
|
"image",
|
||||||
|
"menu",
|
||||||
|
"path",
|
||||||
|
"resources",
|
||||||
|
"tray",
|
||||||
|
"webview",
|
||||||
|
"window",
|
||||||
|
];
|
||||||
|
|
||||||
|
for entry in walkdir::WalkDir::new(tauri_dir.join("capabilities")) {
|
||||||
|
let entry = entry?;
|
||||||
|
let path = entry.path();
|
||||||
|
if path.extension().map_or(false, |ext| ext == "json") {
|
||||||
|
let mut capability = read_to_string(path).context("failed to read capability")?;
|
||||||
|
for plugin in core_plugins {
|
||||||
|
capability = capability.replace(&format!("\"{plugin}:"), &format!("\"core:{plugin}:"));
|
||||||
|
}
|
||||||
|
std::fs::write(path, capability).context("failed to rewrite capability")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn migrate_manifest(manifest: &mut Document) -> Result<()> {
|
||||||
|
let version = "2.0.0-rc.0";
|
||||||
|
|
||||||
|
let dependencies = manifest
|
||||||
|
.as_table_mut()
|
||||||
|
.entry("dependencies")
|
||||||
|
.or_insert(Item::Table(Table::new()))
|
||||||
|
.as_table_mut()
|
||||||
|
.context("manifest dependencies isn't a table")?;
|
||||||
|
|
||||||
|
for dep in [
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin-authenticator",
|
||||||
|
"tauri-plugin-autostart",
|
||||||
|
"tauri-plugin-barcode-scanner",
|
||||||
|
"tauri-plugin-biometric",
|
||||||
|
"tauri-plugin-cli",
|
||||||
|
"tauri-plugin-clipboard-manager",
|
||||||
|
"tauri-plugin-deep-link",
|
||||||
|
"tauri-plugin-dialog",
|
||||||
|
"tauri-plugin-fs",
|
||||||
|
"tauri-plugin-global-shortcut",
|
||||||
|
"tauri-plugin-http",
|
||||||
|
"tauri-plugin-localhost",
|
||||||
|
"tauri-plugin-log",
|
||||||
|
"tauri-plugin-nfc",
|
||||||
|
"tauri-plugin-notification",
|
||||||
|
"tauri-plugin-os",
|
||||||
|
"tauri-plugin-persisted-scope",
|
||||||
|
"tauri-plugin-positioner",
|
||||||
|
"tauri-plugin-process",
|
||||||
|
"tauri-plugin-shell",
|
||||||
|
"tauri-plugin-single-instance",
|
||||||
|
"tauri-plugin-sql",
|
||||||
|
"tauri-plugin-store",
|
||||||
|
"tauri-plugin-stronghold",
|
||||||
|
"tauri-plugin-updater",
|
||||||
|
"tauri-plugin-upload",
|
||||||
|
"tauri-plugin-websocket",
|
||||||
|
"tauri-plugin-window-state",
|
||||||
|
] {
|
||||||
|
migrate_dependency(dependencies, dep, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
let build_dependencies = manifest
|
||||||
|
.as_table_mut()
|
||||||
|
.entry("build-dependencies")
|
||||||
|
.or_insert(Item::Table(Table::new()))
|
||||||
|
.as_table_mut()
|
||||||
|
.context("manifest build-dependencies isn't a table")?;
|
||||||
|
|
||||||
|
migrate_dependency(build_dependencies, "tauri-build", version);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn migrate_dependency(dependencies: &mut Table, name: &str, version: &str) {
|
||||||
|
let item = dependencies.entry(name).or_insert(Item::None);
|
||||||
|
|
||||||
|
// do not rewrite if dependency uses workspace inheritance
|
||||||
|
if item
|
||||||
|
.get("workspace")
|
||||||
|
.and_then(|v| v.as_bool())
|
||||||
|
.unwrap_or_default()
|
||||||
|
{
|
||||||
|
log::info!("`{name}` dependency has workspace inheritance enabled. The features array won't be automatically rewritten.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(dep) = item.as_table_mut() {
|
||||||
|
migrate_dependency_table(dep, version);
|
||||||
|
} else if let Some(Value::InlineTable(table)) = item.as_value_mut() {
|
||||||
|
migrate_dependency_table(table, version);
|
||||||
|
} else if item.as_str().is_some() {
|
||||||
|
*item = Item::Value(version.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn migrate_dependency_table<D: TableLike>(dep: &mut D, version: &str) {
|
||||||
|
*dep.entry("version").or_insert(Item::None) = Item::Value(version.into());
|
||||||
|
}
|
@ -3,32 +3,50 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
helpers::app_paths::{app_dir, tauri_dir},
|
helpers::{
|
||||||
|
app_paths::tauri_dir,
|
||||||
|
cargo_manifest::{crate_version, CargoLock, CargoManifest},
|
||||||
|
},
|
||||||
|
interface::rust::get_workspace_dir,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use std::{fs::read_to_string, str::FromStr};
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
|
||||||
mod config;
|
mod migrations;
|
||||||
mod frontend;
|
|
||||||
mod manifest;
|
|
||||||
|
|
||||||
pub fn command() -> Result<()> {
|
pub fn command() -> Result<()> {
|
||||||
let tauri_dir = tauri_dir();
|
let tauri_dir = tauri_dir();
|
||||||
let app_dir = app_dir();
|
|
||||||
|
|
||||||
let migrated = config::migrate(&tauri_dir).context("Could not migrate config")?;
|
let manifest_contents =
|
||||||
manifest::migrate(&tauri_dir).context("Could not migrate manifest")?;
|
read_to_string(tauri_dir.join("Cargo.toml")).context("failed to read Cargo manifest")?;
|
||||||
frontend::migrate(app_dir, &tauri_dir)?;
|
let manifest = toml::from_str::<CargoManifest>(&manifest_contents)
|
||||||
|
.context("failed to parse Cargo manifest")?;
|
||||||
|
|
||||||
// Add plugins
|
let workspace_dir = get_workspace_dir()?;
|
||||||
for plugin in migrated.plugins {
|
let lock_path = workspace_dir.join("Cargo.lock");
|
||||||
crate::add::command(crate::add::Options {
|
let lock = if lock_path.exists() {
|
||||||
plugin: plugin.clone(),
|
let lockfile_contents = read_to_string(lock_path).context("failed to read Cargo lockfile")?;
|
||||||
branch: None,
|
let lock =
|
||||||
tag: None,
|
toml::from_str::<CargoLock>(&lockfile_contents).context("failed to parse Cargo lockfile")?;
|
||||||
rev: None,
|
Some(lock)
|
||||||
})
|
} else {
|
||||||
.with_context(|| format!("Could not migrate plugin '{plugin}'"))?
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let tauri_version = crate_version(&tauri_dir, Some(&manifest), lock.as_ref(), "tauri").version;
|
||||||
|
let tauri_version = semver::Version::from_str(&tauri_version)?;
|
||||||
|
|
||||||
|
if tauri_version.major == 1 {
|
||||||
|
migrations::v1::run().context("failed to migrate from v1")?;
|
||||||
|
} else if tauri_version.major == 2 {
|
||||||
|
if let Some((pre, _number)) = tauri_version.pre.as_str().split_once('.') {
|
||||||
|
if pre == "beta" {
|
||||||
|
migrations::v2_rc::run().context("failed to migrate from v2 beta to rc")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
Loading…
Reference in New Issue
Block a user