소스 검색

feat: allow config's version to be a path to package.json, closes #2967 (#2971)

Lucas Fernandes Nogueira 3 년 전
부모
커밋
46f2eae8aa
5개의 변경된 파일68개의 추가작업 그리고 7개의 파일을 삭제
  1. 5 0
      .changes/version-package-json.md
  2. 58 3
      core/tauri-utils/src/config.rs
  3. 2 2
      examples/api/src-tauri/Cargo.lock
  4. 1 1
      examples/api/src-tauri/tauri.conf.json
  5. 2 1
      tooling/cli.rs/src/build.rs

+ 5 - 0
.changes/version-package-json.md

@@ -0,0 +1,5 @@
+---
+"tauri": patch
+---
+
+Allow `tauri.conf.json > package > version` to specify a path to a `package.json` file and pull the version from it.

+ 58 - 3
core/tauri-utils/src/config.rs

@@ -10,9 +10,12 @@
 //! This is a core functionality that is not considered part of the stable API.
 //! If you use it, note that it may include breaking changes in the future.
 
-use std::{collections::HashMap, path::PathBuf};
+use std::{collections::HashMap, fmt, fs::read_to_string, path::PathBuf};
 
-use serde::Deserialize;
+use serde::{
+  de::{Deserializer, Error as DeError, Visitor},
+  Deserialize,
+};
 use serde_json::Value as JsonValue;
 use url::Url;
 
@@ -479,16 +482,68 @@ impl Default for BuildConfig {
   }
 }
 
+#[derive(Debug, PartialEq)]
+struct PackageVersion(String);
+
+impl<'d> serde::Deserialize<'d> for PackageVersion {
+  fn deserialize<D: Deserializer<'d>>(deserializer: D) -> Result<PackageVersion, D::Error> {
+    struct PackageVersionVisitor;
+
+    impl<'d> Visitor<'d> for PackageVersionVisitor {
+      type Value = PackageVersion;
+
+      fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+          formatter,
+          "a semver string or a path to a package.json file"
+        )
+      }
+
+      fn visit_str<E: DeError>(self, value: &str) -> Result<PackageVersion, E> {
+        let path = PathBuf::from(value);
+        if path.exists() {
+          let json_str = read_to_string(&path)
+            .map_err(|e| DeError::custom(format!("failed to read version JSON file: {}", e)))?;
+          let package_json: serde_json::Value = serde_json::from_str(&json_str)
+            .map_err(|e| DeError::custom(format!("failed to read version JSON file: {}", e)))?;
+          if let Some(obj) = package_json.as_object() {
+            let version = obj
+              .get("version")
+              .ok_or_else(|| DeError::custom("JSON must contain a `version` field"))?
+              .as_str()
+              .ok_or_else(|| DeError::custom("`version` must be a string"))?;
+            Ok(PackageVersion(version.into()))
+          } else {
+            Err(DeError::custom("value is not a path to a JSON object"))
+          }
+        } else {
+          Ok(PackageVersion(value.into()))
+        }
+      }
+    }
+
+    deserializer.deserialize_string(PackageVersionVisitor {})
+  }
+}
+
 /// The package configuration.
 #[derive(Debug, Default, PartialEq, Deserialize)]
 #[serde(rename_all = "camelCase")]
 pub struct PackageConfig {
   /// App name.
   pub product_name: Option<String>,
-  /// App version.
+  /// App version. It is a semver version number or a path to a `package.json` file contaning the `version` field.
+  #[serde(deserialize_with = "version_deserializer", default)]
   pub version: Option<String>,
 }
 
+fn version_deserializer<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
+where
+  D: Deserializer<'de>,
+{
+  Option::<PackageVersion>::deserialize(deserializer).map(|v| v.map(|v| v.0))
+}
+
 /// The config type mapped to `tauri.conf.json`.
 #[derive(Debug, Default, PartialEq, Deserialize)]
 #[serde(rename_all = "camelCase")]

+ 2 - 2
examples/api/src-tauri/Cargo.lock

@@ -345,9 +345,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "3.0.0-rc.9"
+version = "3.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7843ae7a539bef687e018bf9edf7e87728024b29d02b0f8409726be8880ae1a"
+checksum = "d01c9347757e131122b19cd19a05c85805b68c2352a97b623efdc3c295290299"
 dependencies = [
  "atty",
  "bitflags",

+ 1 - 1
examples/api/src-tauri/tauri.conf.json

@@ -7,7 +7,7 @@
   },
   "package": {
     "productName": "Tauri API",
-    "version": "0.1.0"
+    "version": "../package.json"
   },
   "tauri": {
     "cli": {

+ 2 - 1
tooling/cli.rs/src/build.rs

@@ -56,11 +56,12 @@ pub fn command(options: Options) -> Result<()> {
   } else {
     None
   };
-  let config = get_config(merge_config.as_deref())?;
 
   let tauri_path = tauri_dir();
   set_current_dir(&tauri_path).with_context(|| "failed to change current working directory")?;
 
+  let config = get_config(merge_config.as_deref())?;
+
   let manifest = rewrite_manifest(config.clone())?;
 
   let config_guard = config.lock().unwrap();