Extensions might affect behavior in ways we can’t anticipate,
so just ignoring them is not correct.
Later we’ll add opt-in configuration to ignore specific extensions.
( )
Alphare | |
marmoute |
hg-reviewers |
Extensions might affect behavior in ways we can’t anticipate,
so just ignoring them is not correct.
Later we’ll add opt-in configuration to ignore specific extensions.
No Linters Available |
No Unit Test Coverage |
Path | Packages | |||
---|---|---|---|---|
M | rust/Cargo.lock (4 lines) | |||
M | rust/hg-core/src/config/config.rs (9 lines) | |||
M | rust/hg-core/src/config/layer.rs (8 lines) | |||
M | rust/rhg/Cargo.toml (2 lines) | |||
M | rust/rhg/src/main.rs (26 lines) |
Commit | Parents | Author | Summary | Date |
---|---|---|---|---|
98f6087e5dbc | cc10a4b3bf29 | Simon Sapin | Mar 4 2021, 4:58 AM |
Status | Author | Revision | |
---|---|---|---|
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | D10134 rhg: Add support for --cwd | |
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin |
"crc32fast", | "crc32fast", | ||||
"libc", | "libc", | ||||
"libz-sys", | "libz-sys", | ||||
"miniz_oxide", | "miniz_oxide", | ||||
] | ] | ||||
[[package]] | [[package]] | ||||
name = "format-bytes" | name = "format-bytes" | ||||
version = "0.2.0" | version = "0.2.1" | ||||
source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
checksum = "cc35f5e45d6b31053cea13078ffc6fa52fa8617aa54b7ac2011720d9c009e04f" | checksum = "8030ff4b04f0ca1c612d6fe49f2fc18caf56fb01497cb370b41cfd36d89b3b06" | ||||
dependencies = [ | dependencies = [ | ||||
"format-bytes-macros", | "format-bytes-macros", | ||||
"proc-macro-hack", | "proc-macro-hack", | ||||
] | ] | ||||
[[package]] | [[package]] | ||||
name = "format-bytes-macros" | name = "format-bytes-macros" | ||||
version = "0.3.0" | version = "0.3.0" |
// config.rs | // config.rs | ||||
// | // | ||||
// Copyright 2020 | // Copyright 2020 | ||||
// Valentin Gatien-Baron, | // Valentin Gatien-Baron, | ||||
// Raphaël Gomès <rgomes@octobus.net> | // Raphaël Gomès <rgomes@octobus.net> | ||||
// | // | ||||
// This software may be used and distributed according to the terms of the | // This software may be used and distributed according to the terms of the | ||||
// GNU General Public License version 2 or any later version. | // GNU General Public License version 2 or any later version. | ||||
use super::layer; | use super::layer; | ||||
use super::values; | use super::values; | ||||
use crate::config::layer::{ | use crate::config::layer::{ | ||||
ConfigError, ConfigLayer, ConfigOrigin, ConfigValue, | ConfigError, ConfigLayer, ConfigOrigin, ConfigValue, | ||||
}; | }; | ||||
use crate::utils::files::get_bytes_from_os_str; | use crate::utils::files::get_bytes_from_os_str; | ||||
use format_bytes::{write_bytes, DisplayBytes}; | use format_bytes::{write_bytes, DisplayBytes}; | ||||
use std::collections::HashSet; | |||||
use std::env; | use std::env; | ||||
use std::path::{Path, PathBuf}; | use std::path::{Path, PathBuf}; | ||||
use std::str; | use std::str; | ||||
use crate::errors::{HgResultExt, IoResultExt}; | use crate::errors::{HgResultExt, IoResultExt}; | ||||
/// Holds the config values for the current repository | /// Holds the config values for the current repository | ||||
/// TODO update this docstring once we support more sources | /// TODO update this docstring once we support more sources | ||||
} | } | ||||
if let Some(v) = layer.get(§ion, &item) { | if let Some(v) = layer.get(§ion, &item) { | ||||
return Some((&layer, v)); | return Some((&layer, v)); | ||||
} | } | ||||
} | } | ||||
None | None | ||||
} | } | ||||
/// Return all keys defined for the given section | |||||
pub fn get_section_keys(&self, section: &[u8]) -> HashSet<&[u8]> { | |||||
self.layers | |||||
.iter() | |||||
.flat_map(|layer| layer.iter_keys(section)) | |||||
.collect() | |||||
} | |||||
/// Get raw values bytes from all layers (even untrusted ones) in order | /// Get raw values bytes from all layers (even untrusted ones) in order | ||||
/// of precedence. | /// of precedence. | ||||
#[cfg(test)] | #[cfg(test)] | ||||
fn get_all(&self, section: &[u8], item: &[u8]) -> Vec<&[u8]> { | fn get_all(&self, section: &[u8], item: &[u8]) -> Vec<&[u8]> { | ||||
let mut res = vec![]; | let mut res = vec![]; | ||||
for layer in self.layers.iter().rev() { | for layer in self.layers.iter().rev() { | ||||
if let Some(v) = layer.get(§ion, &item) { | if let Some(v) = layer.get(§ion, &item) { | ||||
res.push(v.bytes.as_ref()); | res.push(v.bytes.as_ref()); |
.insert(item, ConfigValue { bytes: value, line }); | .insert(item, ConfigValue { bytes: value, line }); | ||||
} | } | ||||
/// Returns the config value in `<section>.<item>` if it exists | /// Returns the config value in `<section>.<item>` if it exists | ||||
pub fn get(&self, section: &[u8], item: &[u8]) -> Option<&ConfigValue> { | pub fn get(&self, section: &[u8], item: &[u8]) -> Option<&ConfigValue> { | ||||
Some(self.sections.get(section)?.get(item)?) | Some(self.sections.get(section)?.get(item)?) | ||||
} | } | ||||
/// Returns the keys defined in the given section | |||||
pub fn iter_keys(&self, section: &[u8]) -> impl Iterator<Item = &[u8]> { | |||||
self.sections | |||||
.get(section) | |||||
.into_iter() | |||||
.flat_map(|section| section.keys().map(|vec| &**vec)) | |||||
} | |||||
pub fn is_empty(&self) -> bool { | pub fn is_empty(&self) -> bool { | ||||
self.sections.is_empty() | self.sections.is_empty() | ||||
} | } | ||||
/// Returns a `Vec` of layers in order of precedence (so, in read order), | /// Returns a `Vec` of layers in order of precedence (so, in read order), | ||||
/// recursively parsing the `%include` directives if any. | /// recursively parsing the `%include` directives if any. | ||||
pub fn parse(src: &Path, data: &[u8]) -> Result<Vec<Self>, ConfigError> { | pub fn parse(src: &Path, data: &[u8]) -> Result<Vec<Self>, ConfigError> { | ||||
let mut layers = vec![]; | let mut layers = vec![]; |
chrono = "0.4.19" | chrono = "0.4.19" | ||||
clap = "2.33.1" | clap = "2.33.1" | ||||
derive_more = "0.99" | derive_more = "0.99" | ||||
lazy_static = "1.4.0" | lazy_static = "1.4.0" | ||||
log = "0.4.11" | log = "0.4.11" | ||||
micro-timer = "0.3.1" | micro-timer = "0.3.1" | ||||
regex = "1.3.9" | regex = "1.3.9" | ||||
env_logger = "0.7.1" | env_logger = "0.7.1" | ||||
format-bytes = "0.2.0" | format-bytes = "0.2.1" | ||||
users = "0.11.0" | users = "0.11.0" |
extern crate log; | extern crate log; | ||||
use crate::ui::Ui; | use crate::ui::Ui; | ||||
use clap::App; | use clap::App; | ||||
use clap::AppSettings; | use clap::AppSettings; | ||||
use clap::Arg; | use clap::Arg; | ||||
use clap::ArgMatches; | use clap::ArgMatches; | ||||
use format_bytes::format_bytes; | use format_bytes::{format_bytes, join}; | ||||
use hg::config::Config; | use hg::config::Config; | ||||
use hg::repo::{Repo, RepoError}; | use hg::repo::{Repo, RepoError}; | ||||
use hg::utils::files::{get_bytes_from_os_str, get_path_from_bytes}; | use hg::utils::files::{get_bytes_from_os_str, get_path_from_bytes}; | ||||
use hg::utils::SliceExt; | use hg::utils::SliceExt; | ||||
use std::ffi::OsString; | use std::ffi::OsString; | ||||
use std::path::PathBuf; | use std::path::PathBuf; | ||||
use std::process::Command; | use std::process::Command; | ||||
mod blackbox; | mod blackbox; | ||||
mod error; | mod error; | ||||
mod exitcode; | mod exitcode; | ||||
mod ui; | mod ui; | ||||
use error::CommandError; | use error::CommandError; | ||||
fn main_with_result( | fn main_with_result( | ||||
process_start_time: &blackbox::ProcessStartTime, | process_start_time: &blackbox::ProcessStartTime, | ||||
ui: &ui::Ui, | ui: &ui::Ui, | ||||
repo: Result<&Repo, &NoRepoInCwdError>, | repo: Result<&Repo, &NoRepoInCwdError>, | ||||
config: &Config, | config: &Config, | ||||
) -> Result<(), CommandError> { | ) -> Result<(), CommandError> { | ||||
check_extensions(config)?; | |||||
let app = App::new("rhg") | let app = App::new("rhg") | ||||
.global_setting(AppSettings::AllowInvalidUtf8) | .global_setting(AppSettings::AllowInvalidUtf8) | ||||
.setting(AppSettings::SubcommandRequired) | .setting(AppSettings::SubcommandRequired) | ||||
.setting(AppSettings::VersionlessSubcommands) | .setting(AppSettings::VersionlessSubcommands) | ||||
.arg( | .arg( | ||||
Arg::with_name("repository") | Arg::with_name("repository") | ||||
.help("repository root directory") | .help("repository root directory") | ||||
.short("-R") | .short("-R") | ||||
None => Self::DEFAULT, | None => Self::DEFAULT, | ||||
Some(_) => { | Some(_) => { | ||||
// TODO: warn about unknown config value | // TODO: warn about unknown config value | ||||
Self::DEFAULT | Self::DEFAULT | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
const SUPPORTED_EXTENSIONS: &[&[u8]] = &[b"blackbox", b"share"]; | |||||
fn check_extensions(config: &Config) -> Result<(), CommandError> { | |||||
let enabled = config.get_section_keys(b"extensions"); | |||||
let mut unsupported = enabled; | |||||
for supported in SUPPORTED_EXTENSIONS { | |||||
unsupported.remove(supported); | |||||
} | |||||
if unsupported.is_empty() { | |||||
Ok(()) | |||||
} else { | |||||
Err(CommandError::UnsupportedFeature { | |||||
message: format_bytes!( | |||||
b"extensions: {}", | |||||
join(unsupported, b", ") | |||||
), | |||||
}) | |||||
} | |||||
} |