Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c7704f16 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "aflags: show staged values for each flag." into main

parents c89032cd 46d758bd
Loading
Loading
Loading
Loading
+50 −16
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ fn convert_parsed_flag(flag: &ProtoParsedFlag) -> Flag {
        name,
        container,
        value,
        staged_value: None,
        permission,
        value_picked_from: ValuePickedFrom::Default,
    }
@@ -123,24 +124,56 @@ fn read_device_config_flags() -> Result<HashMap<String, FlagValue>> {
    parse_device_config(&list_output)
}

fn reconcile(pb_flags: &[Flag], dc_flags: HashMap<String, FlagValue>) -> Vec<Flag> {
/// Parse the list of newline-separated staged flags.
///
/// The output is a newline-sepaarated list of entries which follow this format:
///   `namespace*flagname=value`
///
/// The resulting map maps from `namespace/flagname` to `value`, if a staged flag exists for
/// `namespace/flagname`.
fn parse_staged_flags(raw: &str) -> Result<HashMap<String, FlagValue>> {
    let mut flags = HashMap::new();
    for line in raw.split('\n') {
        match (line.find('*'), line.find('=')) {
            (Some(star_index), Some(equal_index)) => {
                let namespace = &line[..star_index];
                let flag = &line[star_index + 1..equal_index];
                if let Ok(value) = FlagValue::try_from(&line[equal_index + 1..]) {
                    flags.insert(namespace.to_owned() + "/" + flag, value);
                }
            }
            _ => continue,
        };
    }
    Ok(flags)
}

fn read_staged_flags() -> Result<HashMap<String, FlagValue>> {
    let staged_flags_output = read_device_config_output(&["list", "staged"])?;
    parse_staged_flags(&staged_flags_output)
}

fn reconcile(
    pb_flags: &[Flag],
    dc_flags: HashMap<String, FlagValue>,
    staged_flags: HashMap<String, FlagValue>,
) -> Vec<Flag> {
    pb_flags
        .iter()
        .map(|f| {
            dc_flags
                .get(&format!("{}/{}.{}", f.namespace, f.package, f.name))
                .map(|value| {
                    if *value == f.value {
                        Flag { value_picked_from: ValuePickedFrom::Default, ..f.clone() }
                    } else {
                        Flag {
                            value_picked_from: ValuePickedFrom::Server,
                            value: *value,
                            ..f.clone()
                        }
                    }
            let server_override = dc_flags.get(&format!("{}/{}", f.namespace, f.qualified_name()));
            let (value_picked_from, selected_value) = match server_override {
                Some(value) if *value != f.value => (ValuePickedFrom::Server, *value),
                _ => (ValuePickedFrom::Default, f.value),
            };
            Flag { value_picked_from, value: selected_value, ..f.clone() }
        })
                .unwrap_or(f.clone())
        .map(|f| {
            let staged_value = staged_flags
                .get(&format!("{}/{}", f.namespace, f.qualified_name()))
                .map(|value| if *value != f.value { Some(*value) } else { None })
                .unwrap_or(None);
            Flag { staged_value, ..f }
        })
        .collect()
}
@@ -149,8 +182,9 @@ impl FlagSource for DeviceConfigSource {
    fn list_flags() -> Result<Vec<Flag>> {
        let pb_flags = read_pb_files()?;
        let dc_flags = read_device_config_flags()?;
        let staged_flags = read_staged_flags()?;

        let flags = reconcile(&pb_flags, dc_flags);
        let flags = reconcile(&pb_flags, dc_flags, staged_flags);
        Ok(flags)
    }

+29 −6
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@ use clap::Parser;
mod device_config_source;
use device_config_source::DeviceConfigSource;

#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Debug)]
enum FlagPermission {
    ReadOnly,
    ReadWrite,
@@ -37,7 +37,7 @@ impl ToString for FlagPermission {
    }
}

#[derive(Clone)]
#[derive(Clone, Debug)]
enum ValuePickedFrom {
    Default,
    Server,
@@ -79,13 +79,14 @@ impl ToString for FlagValue {
    }
}

#[derive(Clone)]
#[derive(Clone, Debug)]
struct Flag {
    namespace: String,
    name: String,
    package: String,
    container: String,
    value: FlagValue,
    staged_value: Option<FlagValue>,
    permission: FlagPermission,
    value_picked_from: ValuePickedFrom,
}
@@ -94,6 +95,13 @@ impl Flag {
    fn qualified_name(&self) -> String {
        format!("{}.{}", self.package, self.name)
    }

    fn display_staged_value(&self) -> String {
        match self.staged_value {
            Some(v) => format!("(->{})", v.to_string()),
            None => "-".to_string(),
        }
    }
}

trait FlagSource {
@@ -110,6 +118,10 @@ Rows in the table from the `list` command follow this format:
  * `package`: package set for this flag in its .aconfig definition.
  * `flag_name`: flag name, also set in definition.
  * `value`: the value read from the flag.
  * `staged_value`: the value on next boot:
    + `-`: same as current value
    + `(->enabled) flipped to enabled on boot.
    + `(->disabled) flipped to disabled on boot.
  * `provenance`: one of:
    + `default`: the flag value comes from its build-time default.
    + `server`: the flag value comes from a server override.
@@ -145,6 +157,7 @@ enum Command {
struct PaddingInfo {
    longest_flag_col: usize,
    longest_val_col: usize,
    longest_staged_val_col: usize,
    longest_value_picked_from_col: usize,
    longest_permission_col: usize,
}
@@ -156,15 +169,20 @@ fn format_flag_row(flag: &Flag, info: &PaddingInfo) -> String {
    let val = flag.value.to_string();
    let p1 = info.longest_val_col + 1;

    let staged_val = flag.display_staged_value();
    let p2 = info.longest_staged_val_col + 1;

    let value_picked_from = flag.value_picked_from.to_string();
    let p2 = info.longest_value_picked_from_col + 1;
    let p3 = info.longest_value_picked_from_col + 1;

    let perm = flag.permission.to_string();
    let p3 = info.longest_permission_col + 1;
    let p4 = info.longest_permission_col + 1;

    let container = &flag.container;

    format!("{full_name:p0$}{val:p1$}{value_picked_from:p2$}{perm:p3$}{container}\n")
    format!(
        "{full_name:p0$}{val:p1$}{staged_val:p2$}{value_picked_from:p3$}{perm:p4$}{container}\n"
    )
}

fn set_flag(qualified_name: &str, value: &str) -> Result<()> {
@@ -188,6 +206,11 @@ fn list() -> Result<String> {
    let padding_info = PaddingInfo {
        longest_flag_col: flags.iter().map(|f| f.qualified_name().len()).max().unwrap_or(0),
        longest_val_col: flags.iter().map(|f| f.value.to_string().len()).max().unwrap_or(0),
        longest_staged_val_col: flags
            .iter()
            .map(|f| f.display_staged_value().len())
            .max()
            .unwrap_or(0),
        longest_value_picked_from_col: flags
            .iter()
            .map(|f| f.value_picked_from.to_string().len())