blob: 4a22471a74be1762868735955a6d8929c0d528d2 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::Result;
use std::fs;
use std::fs::File;
use std::io::{BufRead, BufReader, Error, Write};
use std::ops::Deref;
use std::path::Path;
use uuid::Uuid;
pub use crate::env_info::*;
// TODO(fxbug.dev/66008): use a more explicit variable for the purpose rather
// than the output dir
const TEST_ENV_VAR: &'static str = "FUCHSIA_TEST_OUTDIR";
pub fn is_test_env() -> bool {
std::env::var(TEST_ENV_VAR).is_ok()
}
pub fn is_new_user() -> bool {
!analytics_status_file_exists()
}
pub fn is_opted_in() -> bool {
return read_analytics_status();
}
pub fn opt_in_status(status: &bool) -> Result<()> {
write_analytics_status(status);
if !status {
remove_uuid_file();
}
Ok(())
}
fn analytics_status_file_exists() -> bool {
fs::metadata(Path::new(&analytics_status_path())).is_ok()
}
fn read_analytics_status() -> bool {
read_boolean_from_file(analytics_status_path())
}
fn analytics_status_path() -> String {
path_for_analytics_file("analytics-status")
}
fn read_boolean_from_file(status_file_path: String) -> bool {
return match std::fs::read_to_string(status_file_path) {
Ok(contents) => match contents.trim().parse::<u8>() {
Ok(bool_val) => match bool_val {
0 => false,
1 => true,
_ => false,
},
Err(e) => {
// eprintln!("file value was not parseable as a boolean");
false
}
},
Err(e) => {
// eprintln!("Could not read status file");
false
}
};
}
fn write_analytics_status(status: &bool) {
write_boolean_to_file(status, analytics_status_path())
}
fn write_boolean_to_file(status: &bool, status_file_path: String) {
match fs::create_dir_all(analytics_folder()) {
Ok(x) => match File::create(status_file_path) {
Ok(mut output) => {
let state = match status {
true => 1,
false => 0,
};
writeln!(output, "{}", state);
}
Err(e) => eprintln!("Could not open status file for writing. {:}", e),
},
Err(e) => eprintln!("Could not create directory for status files. {:}", e),
}
}
pub fn uuid() -> String {
match read_uuid() {
Some(uuid) => uuid.to_string().to_owned(),
None => {
let uuid = Uuid::new_v4();
write_uuid(uuid);
uuid.to_string().to_owned()
}
}
}
fn read_uuid() -> Option<Uuid> {
read_uuid_file(uuid_path())
}
fn write_uuid(uuid: Uuid) {
write_uuid_file(uuid, uuid_path())
}
fn uuid_path() -> String {
path_for_analytics_file("uuid")
}
fn remove_uuid_file() {
let path = uuid_path();
let uuid_file = Path::new(&path);
if fs::metadata(&uuid_file).is_ok() {
std::fs::remove_file(uuid_file);
}
}
fn read_uuid_file(status_file_path: String) -> Option<Uuid> {
return match std::fs::read_to_string(status_file_path) {
Ok(contents) => match Uuid::parse_str(&contents.trim()) {
Ok(uuid) => Some(uuid),
Err(e) => None,
},
Err(e) => None,
};
}
fn write_uuid_file(uuid: Uuid, status_file_path: String) {
match fs::create_dir_all(analytics_folder()) {
Ok(x) => match File::create(status_file_path) {
Ok(mut output) => {
writeln!(output, "{}", uuid);
}
Err(e) => eprintln!("Could not open status file for writing"),
},
Err(e) => eprintln!("Could not create directory for status files"),
}
}
pub fn has_opened_ffx_previously() -> bool {
return read_ffx_analytics_status();
}
pub fn set_has_opened_ffx() {
write_ffx_analytics_status();
}
fn read_ffx_analytics_status() -> bool {
read_boolean_from_file(ffx_analytics_status_path())
}
fn ffx_analytics_status_path() -> String {
path_for_analytics_file("ffx")
}
fn write_ffx_analytics_status() {
write_boolean_to_file(&true, ffx_analytics_status_path())
}
#[cfg(test)]
mod test {
use super::*;
#[test]
// Rust tests are run in parallel in threads, which means that this test is
// disruptive to other tests. There's little ROI to doing some kind of fork
// dance here, so the test is included, but not run by default.
#[ignore]
pub fn test_is_test_env() {
std::env::set(TEST_ENV_VAR, "somepath");
assert_eq!(true, is_test_env());
std::env::remove_var(TEST_ENV_VAR);
assert_eq!(false, is_test_env());
}
}