1
0
mirror of https://github.com/Llewellynvdm/starship.git synced 2024-11-24 21:57:41 +00:00

perf(package): only try to read files that exist (#3904)

* perf(package): only try to read files that exist

Have refactored the package module to improve performance. Before this
change the module would try to open every single file that could contain
some package information until it found a valid version. This resulted
in a lot of unneeded disk IO. Have added a new fn, `read_file_from_pwd`
that uses the current context to check if that file already exists and
fast failing if it doesn't. From my local testing this speeds up the
package module from taking ~1ms to ~50µs in an empty directory.

* refactor: move read_file_from_pwd to context

* refactor(haskell): use read_files_from_pwd

* refactor(nodejs): use read_files_from_pwd
This commit is contained in:
Thomas O'Donnell 2022-04-25 16:18:01 +02:00 committed by GitHub
parent 4471e3654c
commit 2a650bfd14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 35 additions and 27 deletions

View File

@ -1,7 +1,7 @@
use crate::config::{ModuleConfig, StarshipConfig}; use crate::config::{ModuleConfig, StarshipConfig};
use crate::configs::StarshipRootConfig; use crate::configs::StarshipRootConfig;
use crate::module::Module; use crate::module::Module;
use crate::utils::{create_command, exec_timeout, CommandOutput}; use crate::utils::{create_command, exec_timeout, read_file, CommandOutput};
use crate::modules; use crate::modules;
use crate::utils::{self, home_dir}; use crate::utils::{self, home_dir};
@ -342,6 +342,18 @@ impl<'a> Context<'a> {
.iter() .iter()
.find_map(|attempt| self.exec_cmd(attempt[0], &attempt[1..])) .find_map(|attempt| self.exec_cmd(attempt[0], &attempt[1..]))
} }
/// Returns the string contents of a file from the current working directory
pub fn read_file_from_pwd(&self, file_name: &str) -> Option<String> {
if !self.try_begin_scan()?.set_files(&[file_name]).is_match() {
log::debug!(
"Not attempting to read {file_name} because, it was not found during scan."
);
return None;
}
read_file(self.current_dir.join(file_name)).ok()
}
} }
#[derive(Debug)] #[derive(Debug)]

View File

@ -2,7 +2,6 @@ use super::{Context, Module, ModuleConfig};
use crate::configs::haskell::HaskellConfig; use crate::configs::haskell::HaskellConfig;
use crate::formatter::StringFormatter; use crate::formatter::StringFormatter;
use crate::utils;
/// Creates a module with the current Haskell version /// Creates a module with the current Haskell version
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> { pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
@ -64,7 +63,7 @@ fn get_snapshot(context: &Context) -> Option<String> {
if !is_stack_project(context) { if !is_stack_project(context) {
return None; return None;
} }
let file_contents = utils::read_file(context.current_dir.join("stack.yaml")).ok()?; let file_contents = context.read_file_from_pwd("stack.yaml")?;
let yaml = yaml_rust::YamlLoader::load_from_str(&file_contents).ok()?; let yaml = yaml_rust::YamlLoader::load_from_str(&file_contents).ok()?;
let version = yaml.first()?["resolver"] let version = yaml.first()?["resolver"]
.as_str() .as_str()

View File

@ -2,7 +2,6 @@ use super::{Context, Module, ModuleConfig};
use crate::configs::nodejs::NodejsConfig; use crate::configs::nodejs::NodejsConfig;
use crate::formatter::{StringFormatter, VersionFormatter}; use crate::formatter::{StringFormatter, VersionFormatter};
use crate::utils;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
@ -10,7 +9,6 @@ use semver::Version;
use semver::VersionReq; use semver::VersionReq;
use serde_json as json; use serde_json as json;
use std::ops::Deref; use std::ops::Deref;
use std::path::Path;
/// Creates a module with the current Node.js version /// Creates a module with the current Node.js version
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> { pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
@ -45,7 +43,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
}) })
.map_style(|variable| match variable { .map_style(|variable| match variable {
"style" => { "style" => {
let engines_version = get_engines_version(&context.current_dir); let engines_version = get_engines_version(context);
let in_engines_range = let in_engines_range =
check_engines_version(nodejs_version.deref().as_ref()?, engines_version); check_engines_version(nodejs_version.deref().as_ref()?, engines_version);
if in_engines_range { if in_engines_range {
@ -87,8 +85,8 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
Some(module) Some(module)
} }
fn get_engines_version(base_dir: &Path) -> Option<String> { fn get_engines_version(context: &Context) -> Option<String> {
let json_str = utils::read_file(base_dir.join("package.json")).ok()?; let json_str = context.read_file_from_pwd("package.json")?;
let package_json: json::Value = json::from_str(&json_str).ok()?; let package_json: json::Value = json::from_str(&json_str).ok()?;
let raw_version = package_json.get("engines")?.get("node")?.as_str()?; let raw_version = package_json.get("engines")?.get("node")?.as_str()?;
Some(raw_version.to_string()) Some(raw_version.to_string())

View File

@ -1,7 +1,6 @@
use super::{Context, Module, ModuleConfig}; use super::{Context, Module, ModuleConfig};
use crate::configs::package::PackageConfig; use crate::configs::package::PackageConfig;
use crate::formatter::{StringFormatter, VersionFormatter}; use crate::formatter::{StringFormatter, VersionFormatter};
use crate::utils;
use ini::Ini; use ini::Ini;
use quick_xml::events::Event as QXEvent; use quick_xml::events::Event as QXEvent;
@ -44,7 +43,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
} }
fn get_node_package_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_node_package_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(&context.current_dir.join("package.json")).ok()?; let file_contents = context.read_file_from_pwd("package.json")?;
let package_json: json::Value = json::from_str(&file_contents).ok()?; let package_json: json::Value = json::from_str(&file_contents).ok()?;
if !config.display_private if !config.display_private
@ -68,7 +67,7 @@ fn get_node_package_version(context: &Context, config: &PackageConfig) -> Option
} }
fn get_poetry_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_poetry_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(&context.current_dir.join("pyproject.toml")).ok()?; let file_contents = context.read_file_from_pwd("pyproject.toml")?;
let poetry_toml: toml::Value = toml::from_str(&file_contents).ok()?; let poetry_toml: toml::Value = toml::from_str(&file_contents).ok()?;
let raw_version = poetry_toml let raw_version = poetry_toml
.get("tool")? .get("tool")?
@ -80,7 +79,7 @@ fn get_poetry_version(context: &Context, config: &PackageConfig) -> Option<Strin
} }
fn get_setup_cfg_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_setup_cfg_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(context.current_dir.join("setup.cfg")).ok()?; let file_contents = context.read_file_from_pwd("setup.cfg")?;
let ini = Ini::load_from_str(&file_contents).ok()?; let ini = Ini::load_from_str(&file_contents).ok()?;
let raw_version = ini.get_from(Some("metadata"), "version")?; let raw_version = ini.get_from(Some("metadata"), "version")?;
@ -92,7 +91,7 @@ fn get_setup_cfg_version(context: &Context, config: &PackageConfig) -> Option<St
} }
fn get_gradle_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_gradle_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(context.current_dir.join("build.gradle")).ok()?; let file_contents = context.read_file_from_pwd("build.gradle")?;
let re = Regex::new(r#"(?m)^version ['"](?P<version>[^'"]+)['"]$"#).unwrap(); let re = Regex::new(r#"(?m)^version ['"](?P<version>[^'"]+)['"]$"#).unwrap();
let caps = re.captures(&file_contents)?; let caps = re.captures(&file_contents)?;
@ -100,7 +99,7 @@ fn get_gradle_version(context: &Context, config: &PackageConfig) -> Option<Strin
} }
fn get_composer_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_composer_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(context.current_dir.join("composer.json")).ok()?; let file_contents = context.read_file_from_pwd("composer.json")?;
let composer_json: json::Value = json::from_str(&file_contents).ok()?; let composer_json: json::Value = json::from_str(&file_contents).ok()?;
let raw_version = composer_json.get("version")?.as_str()?; let raw_version = composer_json.get("version")?.as_str()?;
@ -108,7 +107,7 @@ fn get_composer_version(context: &Context, config: &PackageConfig) -> Option<Str
} }
fn get_julia_project_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_julia_project_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(context.current_dir.join("Project.toml")).ok()?; let file_contents = context.read_file_from_pwd("Project.toml")?;
let project_toml: toml::Value = toml::from_str(&file_contents).ok()?; let project_toml: toml::Value = toml::from_str(&file_contents).ok()?;
let raw_version = project_toml.get("version")?.as_str()?; let raw_version = project_toml.get("version")?.as_str()?;
@ -116,7 +115,7 @@ fn get_julia_project_version(context: &Context, config: &PackageConfig) -> Optio
} }
fn get_helm_package_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_helm_package_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(context.current_dir.join("Chart.yaml")).ok()?; let file_contents = context.read_file_from_pwd("Chart.yaml")?;
let yaml = yaml_rust::YamlLoader::load_from_str(&file_contents).ok()?; let yaml = yaml_rust::YamlLoader::load_from_str(&file_contents).ok()?;
let version = yaml.first()?["version"].as_str()?; let version = yaml.first()?["version"].as_str()?;
@ -124,7 +123,7 @@ fn get_helm_package_version(context: &Context, config: &PackageConfig) -> Option
} }
fn get_mix_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_mix_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(context.current_dir.join("mix.exs")).ok()?; let file_contents = context.read_file_from_pwd("mix.exs")?;
let re = Regex::new(r#"(?m)version: "(?P<version>[^"]+)""#).unwrap(); let re = Regex::new(r#"(?m)version: "(?P<version>[^"]+)""#).unwrap();
let caps = re.captures(&file_contents)?; let caps = re.captures(&file_contents)?;
@ -132,8 +131,8 @@ fn get_mix_version(context: &Context, config: &PackageConfig) -> Option<String>
} }
fn get_maven_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_maven_version(context: &Context, config: &PackageConfig) -> Option<String> {
let pom_file = utils::read_file(context.current_dir.join("pom.xml")).ok()?; let file_contents = context.read_file_from_pwd("pom.xml")?;
let mut reader = QXReader::from_str(&pom_file); let mut reader = QXReader::from_str(&file_contents);
reader.trim_text(true); reader.trim_text(true);
let mut buf = vec![]; let mut buf = vec![];
@ -171,8 +170,8 @@ fn get_maven_version(context: &Context, config: &PackageConfig) -> Option<String
} }
fn get_meson_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_meson_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(context.current_dir.join("meson.build")) let file_contents = context
.ok()? .read_file_from_pwd("meson.build")?
.split_ascii_whitespace() .split_ascii_whitespace()
.collect::<String>(); .collect::<String>();
@ -183,14 +182,14 @@ fn get_meson_version(context: &Context, config: &PackageConfig) -> Option<String
} }
fn get_vmod_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_vmod_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(context.current_dir.join("v.mod")).ok()?; let file_contents = context.read_file_from_pwd("v.mod")?;
let re = Regex::new(r"(?m)^\s*version\s*:\s*'(?P<version>[^']+)'").unwrap(); let re = Regex::new(r"(?m)^\s*version\s*:\s*'(?P<version>[^']+)'").unwrap();
let caps = re.captures(&file_contents)?; let caps = re.captures(&file_contents)?;
format_version(&caps["version"], config.version_format) format_version(&caps["version"], config.version_format)
} }
fn get_vpkg_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_vpkg_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(context.current_dir.join("vpkg.json")).ok()?; let file_contents = context.read_file_from_pwd("vpkg.json")?;
let vpkg_json: json::Value = json::from_str(&file_contents).ok()?; let vpkg_json: json::Value = json::from_str(&file_contents).ok()?;
let raw_version = vpkg_json.get("version")?.as_str()?; let raw_version = vpkg_json.get("version")?.as_str()?;
@ -198,14 +197,14 @@ fn get_vpkg_version(context: &Context, config: &PackageConfig) -> Option<String>
} }
fn get_sbt_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_sbt_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(context.current_dir.join("build.sbt")).ok()?; let file_contents = context.read_file_from_pwd("build.sbt")?;
let re = Regex::new(r"(?m)^(.*/)*\s*version\s*:=\s*.(?P<version>[\d\.]+)").unwrap(); let re = Regex::new(r"(?m)^(.*/)*\s*version\s*:=\s*.(?P<version>[\d\.]+)").unwrap();
let caps = re.captures(&file_contents)?; let caps = re.captures(&file_contents)?;
format_version(&caps["version"], config.version_format) format_version(&caps["version"], config.version_format)
} }
fn get_cargo_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_cargo_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(&context.current_dir.join("Cargo.toml")).ok()?; let file_contents = context.read_file_from_pwd("Cargo.toml")?;
let cargo_toml: toml::Value = toml::from_str(&file_contents).ok()?; let cargo_toml: toml::Value = toml::from_str(&file_contents).ok()?;
let raw_version = cargo_toml.get("package")?.get("version")?.as_str()?; let raw_version = cargo_toml.get("package")?.get("version")?.as_str()?;
@ -231,7 +230,7 @@ fn get_nimble_version(context: &Context, config: &PackageConfig) -> Option<Strin
} }
fn get_shard_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_shard_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(&context.current_dir.join("shard.yml")).ok()?; let file_contents = context.read_file_from_pwd("shard.yml")?;
let data = yaml_rust::YamlLoader::load_from_str(&file_contents).ok()?; let data = yaml_rust::YamlLoader::load_from_str(&file_contents).ok()?;
let raw_version = data.first()?["version"].as_str()?; let raw_version = data.first()?["version"].as_str()?;
@ -240,7 +239,7 @@ fn get_shard_version(context: &Context, config: &PackageConfig) -> Option<String
} }
fn get_dart_pub_version(context: &Context, config: &PackageConfig) -> Option<String> { fn get_dart_pub_version(context: &Context, config: &PackageConfig) -> Option<String> {
let file_contents = utils::read_file(&context.current_dir.join("pubspec.yaml")).ok()?; let file_contents = context.read_file_from_pwd("pubspec.yaml")?;
let data = yaml_rust::YamlLoader::load_from_str(&file_contents).ok()?; let data = yaml_rust::YamlLoader::load_from_str(&file_contents).ok()?;
let raw_version = data.first()?["version"].as_str()?; let raw_version = data.first()?["version"].as_str()?;