ronantakizawa/codereview-bench huggingface dataset:
Repository: tauri-apps/tauri
File: core/tauri/src/window/menu.rs (Rust)

Code before:
impl<R: Runtime> Clone for MenuItemHandle<R> {
  fn clone(&self) -> Self {
    Self {
      id: self.id,
      dispatcher: self.dispatcher.clone(),
    }
  }
}

impl<R: Runtime> MenuHandle<R> {
  /// Gets a handle to the menu item that has the specified `id`.
  pub fn get_item(&self, id: MenuIdRef<'_>) -> MenuItemHandle<R> {
    let ids = self.ids.lock().unwrap();
    let iter = ids.iter();
    for (raw, item_id) in iter {
      if item_id == id {
        return MenuItemHandle {
          id: *raw,
          dispatcher: self.dispatcher.clone(),
        };
      }
    }
    panic!("item id not found")
  }

  /// Gets an Option<handle> to the menu item that has the specified `id`.
  pub fn try_get_item(&self, id: MenuIdRef<'_>) -> Option<MenuItemHandle<R>> {
    self.ids.lock().unwrap().iter().find(|i|i.1 == id).map(|i| MenuItemHandle {
        id: *i.0,
        dispatcher: self.dispatcher.clone(),
       })
  }

  /// Shows the menu.
  pub fn show(&self) -> crate::Result<()> {
    self.dispatcher.show_menu().map_err(Into::into)
  }

  /// Hides the menu.
  pub fn hide(&self) -> crate::Result<()> {
    self.dispatcher.hide_menu().map_err(Into::into)
  }

  /// Whether the menu is visible or not.
  pub fn is_visible(&self) -> crate::Result<bool> {
    self.dispatcher.is_menu_visible().map_err(Into::into)
  }

  /// Toggles the menu visibility.
  pub fn toggle(&self) -> crate::Result<()> {
    if self.is_visible()? {

Review comment (suggestion):
```suggestion
  /// Attempts to get a handle to the menu item that has the specified `id`, return an error if `id` is not found.
```

Code after:
impl<R: Runtime> Clone for MenuItemHandle<R> {
  fn clone(&self) -> Self {
    Self {
      id: self.id,
      dispatcher: self.dispatcher.clone(),
    }
  }
}

impl<R: Runtime> MenuHandle<R> {
  /// Gets a handle to the menu item that has the specified `id`.
  pub fn get_item(&self, id: MenuIdRef<'_>) -> MenuItemHandle<R> {
    let ids = self.ids.lock().unwrap();
    let iter = ids.iter();
    for (raw, item_id) in iter {
      if item_id == id {
        return MenuItemHandle {
          id: *raw,
          dispatcher: self.dispatcher.clone(),
        };
      }
    }
    panic!("item id not found")
  }

  /// Attempts to get a handle to the menu item that has the specified `id`, return an error if `id` is not found.
  pub fn try_get_item(&self, id: MenuIdRef<'_>) -> Option<MenuItemHandle<R>> {
    self
      .ids
      .lock()
      .unwrap()
      .iter()
      .find(|i| i.1 == id)
      .map(|i| MenuItemHandle {
        id: *i.0,
        dispatcher: self.dispatcher.clone(),
      })
  }

  /// Shows the menu.
  pub fn show(&self) -> crate::Result<()> {
    self.dispatcher.show_menu().map_err(Into::into)
  }

  /// Hides the menu.
  pub fn hide(&self) -> crate::Result<()> {
    self.dispatcher.hide_menu().map_err(Into::into)
  }

  /// Whether the menu is visible or not.
  pub fn is_visible(&self) -> crate::Result<bool> {
Repository: tauri-apps/tauri
File: tooling/bundler/src/bundle/windows/nsis.rs (Rust)

Code before:
      .join("ApplicationID.dll"),
    nsis_plugins.join("x86-unicode").join("ApplicationID.dll"),
  )?;

  let data = download_and_verify(NSIS_TAURI_UTILS, NSIS_TAURI_UTILS_SHA1, HashAlgorithm::Sha1)?;
  write(
    nsis_plugins
      .join("x86-unicode")
      .join("nsis_tauri_utils.dll"),
    data,
  )?;

  Ok(())
}

fn add_build_number_if_needed(version_str: &str) -> anyhow::Result<String> {
  let version = semver::Version::parse(version_str).context("invalid app version")?;
  if !version.build.is_empty() {
    let build = version.build.parse::<u64>();
    if build.is_ok() {
      return Ok(format!(
        "{}.{}.{}.{}",
        version.major, version.minor, version.patch, version.build
      ));
    } else {
      anyhow::bail!("optional build metadata in app version must be numeric-only and cannot be greater than 65535 for msi target");
    }
  }

  Ok(format!(
    "{}.{}.{}.0",
    version.major, version.minor, version.patch,
  ))
}
fn build_nsis_app_installer(
  settings: &Settings,
  _nsis_toolset_path: &Path,
  tauri_tools_path: &Path,
  updater: bool,
) -> crate::Result<Vec<PathBuf>> {
  let arch = match settings.binary_arch() {
    "x86_64" => "x64",
    "x86" => "x86",
    "aarch64" => "arm64",
    target => {
      return Err(crate::Error::ArchError(format!(
        "unsupported target: {}",
        target
      )))
    }
  };

Review comment (suggestion):
```suggestion
      anyhow::bail!("optional build metadata in app version must be numeric-only");
```

Code after:
  copy(
    nsis_plugins
      .join("ReleaseUnicode")
      .join("ApplicationID.dll"),
    nsis_plugins.join("x86-unicode").join("ApplicationID.dll"),
  )?;

  let data = download_and_verify(NSIS_TAURI_UTILS, NSIS_TAURI_UTILS_SHA1, HashAlgorithm::Sha1)?;
  write(
    nsis_plugins
      .join("x86-unicode")
      .join("nsis_tauri_utils.dll"),
    data,
  )?;

  Ok(())
}

fn add_build_number_if_needed(version_str: &str) -> anyhow::Result<String> {
  let version = semver::Version::parse(version_str).context("invalid app version")?;
  if !version.build.is_empty() {
    let build = version.build.parse::<u64>();
    if build.is_ok() {
      return Ok(format!(
        "{}.{}.{}.{}",
        version.major, version.minor, version.patch, version.build
      ));
    } else {
      anyhow::bail!("optional build metadata in app version must be numeric-only");
    }
  }

  Ok(format!(
    "{}.{}.{}.0",
    version.major, version.minor, version.patch,
  ))
}
fn build_nsis_app_installer(
  settings: &Settings,
  _nsis_toolset_path: &Path,
  tauri_tools_path: &Path,
  updater: bool,
) -> crate::Result<Vec<PathBuf>> {
  let arch = match settings.binary_arch() {
    "x86_64" => "x64",
    "x86" => "x86",
    "aarch64" => "arm64",
    target => {
      return Err(crate::Error::ArchError(format!(
        "unsupported target: {}",
        target
Repository: tauri-apps/tauri
File: tooling/api/src/tauri.ts (TypeScript)

Code before:
 *
 * @since 1.0.0
 */
function transformCallback(
  callback?: (response: any) => void,
  once = false
): number {
  const identifier = uid()
  const prop = `_${identifier}`

  Object.defineProperty(window, prop, {
    value: (result: any) => {
      if (once) {
        Reflect.deleteProperty(window, prop)
      }

      return callback?.(result)
    },
    writable: false,
    configurable: true
  })

  return identifier
}

class Channel {
  id: number

  constructor(id: number) {
    this.id = id
  }

  toJSON(): string {
    return `__CHANNEL__:${this.id}`
  }
}

/**
 * Creates a channel using the given handler function.
 *
 * @returns the channel to send to the IPC.
 *
 * @since 2.0.0
 */
function channel(fn: (response: any) => void): Channel {
  return new Channel(transformCallback(fn))
}

/**
 * Command arguments.
 *

Review comment (refactor):
I would refactor this to be more similar to the `Websocket` or `BroadcastChannel` api i.e. the constructor takes no arguments and you can listen to events by overriding the `on message` property or calling `.addEventListener('message', () => {})`

Code after:
 *
 * @since 1.0.0
 */
function transformCallback(
  callback?: (response: any) => void,
  once = false
): number {
  const identifier = uid()
  const prop = `_${identifier}`

  Object.defineProperty(window, prop, {
    value: (result: any) => {
      if (once) {
        Reflect.deleteProperty(window, prop)
      }

      return callback?.(result)
    },
    writable: false,
    configurable: true
  })

  return identifier
}

class Channel<T = unknown> {
  id: number
  // @ts-expect-error field used by the IPC serializer
  private readonly __TAURI_CHANNEL_MARKER__ = true
  #onmessage: (response: T) => void = () => {
    // no-op
  }

  constructor() {
    this.id = transformCallback((response: T) => {
      this.#onmessage(response)
    })
  }

  set onmessage(handler: (response: T) => void) {
    this.#onmessage = handler
  }

  get onmessage(): (response: T) => void {
    return this.#onmessage
  }

  toJSON(): string {
    return `__CHANNEL__:${this.id}`
  }
}
Repository: tauri-apps/tauri
File: core/tauri/src/path/desktop.rs (Rust)

Code before:
  /// ## Platform-specific
  ///
  /// - **Linux:** Resolves to [`data_local_dir`]`/${bundle_identifier}/logs`.
  /// - **macOS:** Resolves to [`home_dir`]`/Library/Logs/${bundle_identifier}`
  /// - **Windows:** Resolves to [`data_local_dir`]`/${bundle_identifier}/logs`.
  pub fn app_log_dir(&self) -> Result<PathBuf> {
    #[cfg(target_os = "macos")]
    let path = dirs_next::home_dir().ok_or(Error::UnknownPath).map(|dir| {
      dir
        .join("Library/Logs")
        .join(&self.0.config().tauri.bundle.identifier)
    });

    #[cfg(not(target_os = "macos"))]
    let path = dirs_next::data_local_dir()
      .ok_or(Error::UnknownPath)
      .map(|dir| {
        dir
          .join(&self.0.config().tauri.bundle.identifier)
          .join("logs")
      });

    path
  }

  /// A temporary directory. Resolves to [`temp_dir`].
  pub fn temp_dir(&self) -> Result<PathBuf> {
    Ok(std::env::temp_dir())
  }
}


Review comment (suggestion):
```suggestion
  /// A temporary directory. Resolves to [`std::env::temp_dir`].
```

Code after:
  /// ## Platform-specific
  ///
  /// - **Linux:** Resolves to [`data_local_dir`]`/${bundle_identifier}/logs`.
  /// - **macOS:** Resolves to [`home_dir`]`/Library/Logs/${bundle_identifier}`
  /// - **Windows:** Resolves to [`data_local_dir`]`/${bundle_identifier}/logs`.
  pub fn app_log_dir(&self) -> Result<PathBuf> {
    #[cfg(target_os = "macos")]
    let path = dirs_next::home_dir().ok_or(Error::UnknownPath).map(|dir| {
      dir
        .join("Library/Logs")
        .join(&self.0.config().tauri.bundle.identifier)
    });

    #[cfg(not(target_os = "macos"))]
    let path = dirs_next::data_local_dir()
      .ok_or(Error::UnknownPath)
      .map(|dir| {
        dir
          .join(&self.0.config().tauri.bundle.identifier)
          .join("logs")
      });

    path
  }

  /// A temporary directory. Resolves to [`std::env::temp_dir`].
  pub fn temp_dir(&self) -> Result<PathBuf> {
    Ok(std::env::temp_dir())
  }
}
Repository: tauri-apps/tauri
File: .scripts/ci/check-change-tags.js (JavaScript)

Code before:

const missingTagsFiles = {}

const changeFiles = fs
  .readdirSync('.changes')
  .filter((f) => f.endsWith('.md') && f.toLowerCase() !== 'readme.md')
for (const file of changeFiles) {
  const content = fs.readFileSync(path.join('.changes', file), 'utf8')
  const [frontMatter] = /^---[\s\S.]*---\n/i.exec(content)
  const packages = frontMatter
    .split('\n')
    .filter((l) => !(l === '---' || !l))
    .map((l) => l.split(':'))

  for (const [p, _, tag] of packages) {
    const package = p.replace(/('|")/g, '')
    if (ignorePackages.includes(package)) continue
    if (!tag) {
      if (!missingTagsFiles[file]) missingTagsFiles[file] = []
      missingTagsFiles[file].push(package)
    }
  }
}

if (Object.keys(missingTagsFiles).length !== 0) {
  for (const [file, packages] of Object.entries(missingTagsFiles)) {
    for (const package of packages) {
      console.error(
        `Package \`${package}\` is missing a change tag in ${path.join(
          '.changes',
          file
        )} `
      )
    }
  }
  process.exit(1)
}


Review comment (suggestion):
```suggestion
const entries = Object.entries(missingTagsFiles)
if (entries.length > 0) {
  for (const [file, packages] of entries) {
```

Code after:

const covectorConfig = JSON.parse(
  fs.readFileSync('.changes/config.json', 'utf8')
)
const tags = Object.keys(covectorConfig.changeTags)

const missingTagsFiles = {}
const unknownTagsFiles = {}

function checkChangeFiles(changeFiles) {
  for (const file of changeFiles) {
    const content = fs.readFileSync(file, 'utf8')
    const [frontMatter] = /^---[\s\S.]*---\n/i.exec(content)
    const packages = frontMatter
      .split('\n')
      .filter((l) => !(l === '---' || !l))
      .map((l) => l.replace(/('|")/g, '').split(':'))

    for (const [package, _, tag] of packages) {
      if (!tag) {
        if (ignorePackages.includes(package)) continue

        if (!missingTagsFiles[file]) missingTagsFiles[file] = []
        missingTagsFiles[file].push(package)
      } else if (!tags.includes(tag)) {
        if (!unknownTagsFiles[file]) unknownTagsFiles[file] = []
        unknownTagsFiles[file].push({ package, tag })
      }
    }
  }
  const missingTagsEntries = Object.entries(missingTagsFiles)
  const unknownTagsEntries = Object.entries(unknownTagsFiles)
  if (missingTagsEntries.length > 0 || unknownTagsEntries.length > 0) {
    for (const [file, packages] of missingTagsEntries) {
      for (const package of packages) {
        console.error(
          `Package \`${package}\` is missing a change tag in ${file} `
        )
      }
    }

    for (const [file, packages] of unknownTagsEntries) {
      for (const { package, tag } of packages) {
        console.error(
          `Package \`${package}\` has an uknown change tag ${tag} in ${file} `
        )
      }
    }

    process.exit(1)
  }
Repository: tauri-apps/tauri
File: core/tauri/src/updater/mod.rs (Rust)

Code before:
    ),
  );

  if should_install {
    let handle = update.app.clone();
    let handle_ = handle.clone();

    // Launch updater download process
    // macOS we display the `Ready to restart dialog` asking to restart
    // Windows is closing the current App and launch the downloaded MSI when ready (the process stop here)
    // Linux we replace the AppImage by launching a new install, it start a new AppImage instance, so we're closing the previous. (the process stop here)
    let update_result = update
      .download_and_install(
        pubkey.clone(),
        move |chunk_length, content_length| {
          send_download_progress_event(&handle, chunk_length, content_length);
        },
        move || {
          send_status_update(&handle_, UpdaterEvent::Downloaded);
        },
      )
      .await;

    if let Err(err) = &update_result {
      // emit {"status": "ERROR", "error": "The error message"}
      send_status_update(&update.app, UpdaterEvent::Error(err.to_string()));
    } else {
      // emit {"status": "DONE"}
      send_status_update(&update.app, UpdaterEvent::Updated);

      // Ask user if we need to restart the application
      let should_exit = ask(
        parent_window,
        "Ready to Restart",
        "The installation was successful, do you want to restart the application now?",
      );
      if should_exit {
        update.app.restart();
      }
    }
  }

  Ok(())
}


Review comment (suggestion):
It's ok for `prompt_for_install` to return an error, the caller already checks the error and emits the event.

Code after:
    ),
  );

  if should_install {
    let handle = update.app.clone();
    let handle_ = handle.clone();

    // Launch updater download process
    // macOS we display the `Ready to restart dialog` asking to restart
    // Windows is closing the current App and launch the downloaded MSI when ready (the process stop here)
    // Linux we replace the AppImage by launching a new install, it start a new AppImage instance, so we're closing the previous. (the process stop here)
    update
      .download_and_install(
        pubkey.clone(),
        move |chunk_length, content_length| {
          send_download_progress_event(&handle, chunk_length, content_length);
        },
        move || {
          send_status_update(&handle_, UpdaterEvent::Downloaded);
        },
      )
      .await?;

    // emit {"status": "DONE"}
    send_status_update(&update.app, UpdaterEvent::Updated);

    // Ask user if we need to restart the application
    let should_exit = ask(
      parent_window,
      "Ready to Restart",
      "The installation was successful, do you want to restart the application now?",
    );
    if should_exit {
      update.app.restart();
    }
  }

  Ok(())
}
Repository: tauri-apps/tauri
File: core/tauri/src/manager.rs (Rust)

Code before:

  pub(crate) fn on_window_close(&self, label: &str) {
    self.windows_lock().remove(label);
  }

  pub fn emit_filter<S, F>(
    &self,
    event: &str,
    source_window_label: Option<&str>,
    payload: S,
    filter: F,
  ) -> crate::Result<()>
  where
    S: Serialize + Clone,
    F: Fn(&Window<R>) -> bool,
  {
    assert_event_name_is_valid(event);
    println!("emit {event}");
    self
      .windows_lock()
      .values()
      .filter(|&w| filter(w))
      .try_for_each(|window| {
        println!("trigger!!");
        window.emit_internal(event, source_window_label, payload.clone())
      })
  }

  pub fn eval_script_all<S: Into<String>>(&self, script: S) -> crate::Result<()> {
    let script = script.into();
    self
      .windows_lock()
      .values()
      .try_for_each(|window| window.eval(&script))
  }

  pub fn labels(&self) -> HashSet<String> {
    self.windows_lock().keys().cloned().collect()
  }

  pub fn config(&self) -> Arc<Config> {
    self.inner.config.clone()
  }

  pub fn package_info(&self) -> &PackageInfo {
    &self.inner.package_info
  }

  pub fn unlisten(&self, handler_id: EventHandler) {
    self.inner.listeners.unlisten(handler_id)
  }

Review comment (suggestion):
```suggestion
      .try_for_each(|window| window.emit_internal(event, source_window_label, payload.clone()))
```

Code after:

  pub(crate) fn on_window_close(&self, label: &str) {
    self.windows_lock().remove(label);
  }

  pub fn emit_filter<S, F>(
    &self,
    event: &str,
    source_window_label: Option<&str>,
    payload: S,
    filter: F,
  ) -> crate::Result<()>
  where
    S: Serialize + Clone,
    F: Fn(&Window<R>) -> bool,
  {
    assert_event_name_is_valid(event);
    self
      .windows_lock()
      .values()
      .filter(|&w| filter(w))
      .try_for_each(|window| window.emit_internal(event, source_window_label, payload.clone()))
  }

  pub fn eval_script_all<S: Into<String>>(&self, script: S) -> crate::Result<()> {
    let script = script.into();
    self
      .windows_lock()
      .values()
      .try_for_each(|window| window.eval(&script))
  }

  pub fn labels(&self) -> HashSet<String> {
    self.windows_lock().keys().cloned().collect()
  }

  pub fn config(&self) -> Arc<Config> {
    self.inner.config.clone()
  }

  pub fn package_info(&self) -> &PackageInfo {
    &self.inner.package_info
  }

  pub fn unlisten(&self, handler_id: EventHandler) {
    self.inner.listeners.unlisten(handler_id)
  }

  pub fn trigger(&self, event: &str, window: Option<String>, data: Option<String>) {
    assert_event_name_is_valid(event);
    self.inner.listeners.trigger(event, window, data)
Repository: tauri-apps/tauri
File: core/tauri/src/updater/core.rs (Rust)

Code before:
use std::io::Seek;
use std::{
  collections::HashMap,
  env,
  fmt::{self},
  io::{Cursor, Read},
  path::{Path, PathBuf},
  str::{from_utf8, FromStr},
  time::Duration,
};

#[cfg(any(target_os = "linux", windows))]
use std::ffi::OsStr;

#[cfg(all(desktop, not(target_os = "windows")))]
use crate::api::file::Compression;

#[cfg(target_os = "windows")]
use std::{
  fs::read_dir,
  os::windows::process::CommandExt,
  process::{exit, Command},
};

#[cfg(target_os = "windows")]
use windows::Win32::System::Threading::DETACHED_PROCESS;

type ShouldInstall = dyn FnOnce(&Version, &RemoteRelease) -> bool + Send;

#[derive(Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum RemoteReleaseInner {
  Dynamic(ReleaseManifestPlatform),
  Static {
    platforms: HashMap<String, ReleaseManifestPlatform>,
  },
}

/// Information about a release returned by the remote update server.
///
/// This type can have one of two shapes: Server Format (Dynamic Format) and Static Format.
#[derive(Debug)]
pub struct RemoteRelease {
  /// Version to install.
  version: Version,
  /// Release notes.
  notes: Option<String>,
  /// Release date.
  pub_date: Option<OffsetDateTime>,
  /// Release data.
  data: RemoteReleaseInner,

Review comment (suggestion):
from my testings, `DETACHEDPROCESS` was not needed when invoking `cmd` or `powershell` because they bother will call either `start` or `Start-Process` which will launch the installer in a detached process already.

Code after:
use std::io::Seek;
use std::{
  collections::HashMap,
  env,
  fmt::{self},
  io::{Cursor, Read},
  path::{Path, PathBuf},
  str::{from_utf8, FromStr},
  time::Duration,
};

#[cfg(any(target_os = "linux", windows))]
use std::ffi::OsStr;

#[cfg(all(desktop, not(target_os = "windows")))]
use crate::api::file::Compression;

#[cfg(target_os = "windows")]
use std::{
  fs::read_dir,
  process::{exit, Command},
};

type ShouldInstall = dyn FnOnce(&Version, &RemoteRelease) -> bool + Send;

#[derive(Debug, Deserialize, Serialize)]
#[serde(untagged)]
pub enum RemoteReleaseInner {
  Dynamic(ReleaseManifestPlatform),
  Static {
    platforms: HashMap<String, ReleaseManifestPlatform>,
  },
}

/// Information about a release returned by the remote update server.
///
/// This type can have one of two shapes: Server Format (Dynamic Format) and Static Format.
#[derive(Debug)]
pub struct RemoteRelease {
  /// Version to install.
  version: Version,
  /// Release notes.
  notes: Option<String>,
  /// Release date.
  pub_date: Option<OffsetDateTime>,
  /// Release data.
  data: RemoteReleaseInner,
}

impl<'de> Deserialize<'de> for RemoteRelease {
  fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
Repository: tauri-apps/tauri
File: tooling/cli/src/lib.rs (Rust)

Code before:
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

//! [![](https://github.com/tauri-apps/tauri/raw/dev/.github/splash.png)](https://tauri.app)
//!
//! This rust executable provides the full interface to all of the required activities for which the CLI is required. It will run on macOS, Windows, and Linux.

#![doc(
  html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png",
  html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
)]

pub use anyhow::Result;

mod build;
mod completions;
mod dev;
mod helpers;
mod icon;
mod info;
mod init;
mod interface;
mod migrate;
mod mobile;
mod plugin;
mod signer;

use clap::{ArgAction, CommandFactory, FromArgMatches, Parser, Subcommand, ValueEnum};
use env_logger::fmt::Color;
use env_logger::Builder;
use log::{debug, log_enabled, Level};

Review comment (suggestion):
```suggestion
//! This Rust executable provides the full interface to all of the required activities for which the CLI is required. It will run on macOS, Windows, and Linux.
```

Code after:
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

//! [![](https://github.com/tauri-apps/tauri/raw/dev/.github/splash.png)](https://tauri.app)
//!
//! This Rust executable provides the full interface to all of the required activities for which the CLI is required. It will run on macOS, Windows, and Linux.

#![doc(
  html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png",
  html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/app-icon.png"
)]

pub use anyhow::Result;

mod build;
mod completions;
mod dev;
mod helpers;
mod icon;
mod info;
mod init;
mod interface;
mod migrate;
mod mobile;
mod plugin;
mod signer;

use clap::{ArgAction, CommandFactory, FromArgMatches, Parser, Subcommand, ValueEnum};
use env_logger::fmt::Color;
use env_logger::Builder;
use log::{debug, log_enabled, Level};