Skip to content

Commit

Permalink
🍴 Fetch entities in parallel for real (#70)
Browse files Browse the repository at this point in the history
- 🍴 Fetch entities in parallel for real

* Futures are cold, JS brain gaslight me

* Use ResultWithDefaultError where applicable

---

Co-authored-by: William Barbosa <[email protected]>
  • Loading branch information
shantanuraj and heytherewill authored Dec 12, 2023
1 parent 373a0e2 commit e24659e
Show file tree
Hide file tree
Showing 13 changed files with 100 additions and 79 deletions.
32 changes: 16 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 14 additions & 11 deletions src/api/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,18 @@ impl V9ApiClient {
let header_content =
"Basic ".to_string() + general_purpose::STANDARD.encode(auth_string).as_str();
let mut headers = header::HeaderMap::new();
let auth_header = header::HeaderValue::from_str(header_content.as_str())?;
let auth_header = header::HeaderValue::from_str(header_content.as_str()).expect("Invalid header value");
headers.insert(header::AUTHORIZATION, auth_header);

let base_client = Client::builder().default_headers(headers);
let http_client = {
if let Some(proxy) = proxy {
base_client.proxy(reqwest::Proxy::all(proxy)?)
base_client.proxy(reqwest::Proxy::all(proxy).expect("Invalid proxy"))
} else {
base_client
}
}
.build()?;
.build().expect("Couldn't build a http client");
let api_client = Self {
http_client,
base_url: "https://track.toggl.com/api/v9".to_string(),
Expand Down Expand Up @@ -140,13 +140,16 @@ impl ApiClient for V9ApiClient {
}

async fn get_entities(&self) -> ResultWithDefaultError<Entities> {
let network_time_entries = self.get_time_entries();
let network_projects = self.get_projects();
let network_tasks = self.get_tasks();
let network_clients = self.get_clients();
let (network_time_entries, network_projects, network_tasks, network_clients) =
tokio::join!(
self.get_time_entries(),
self.get_projects(),
self.get_tasks(),
self.get_clients(),
);

let clients: HashMap<i64, crate::models::Client> = network_clients
.await?
.unwrap_or_default()
.iter()
.map(|c| {
(
Expand All @@ -161,7 +164,7 @@ impl ApiClient for V9ApiClient {
.collect();

let projects: HashMap<i64, Project> = network_projects
.await?
.unwrap_or_default()
.iter()
.map(|p| {
(
Expand All @@ -183,7 +186,7 @@ impl ApiClient for V9ApiClient {
.collect();

let tasks: HashMap<i64, Task> = network_tasks
.await?
.unwrap_or_default()
.iter()
.map(|t| {
(
Expand All @@ -199,7 +202,7 @@ impl ApiClient for V9ApiClient {
.collect();

let time_entries = network_time_entries
.await?
.unwrap_or_default()
.iter()
.map(|te| TimeEntry {
id: te.id,
Expand Down
2 changes: 1 addition & 1 deletion src/commands/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl AuthenticationCommand {
"{} {}",
AUTH_SUCCEEDED_MESSAGE.green(),
user.email.green().bold(),
)?;
).expect("failed to write to stdout");

Ok(())
}
Expand Down
6 changes: 3 additions & 3 deletions src/config/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ impl ConfigInitCommand {
match config_path {
Ok(path) => {
if edit {
utilities::open_path_in_editor(path)?
utilities::open_path_in_editor(path)?;
} else {
let display_path = utilities::simplify_config_path_for_display(path.as_path());
println!(
Expand All @@ -30,8 +30,8 @@ impl ConfigInitCommand {
"Created config at".green().bold(),
display_config_path
);
std::fs::create_dir_all(config_dir)?;
std::fs::write(config_path, default_config)?;
std::fs::create_dir_all(config_dir).expect("failed to create config directory");
std::fs::write(config_path, default_config).expect("failed to write config");
println!("{}", msg);
}
}
Expand Down
16 changes: 8 additions & 8 deletions src/config/locate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ use std::path::{Path, PathBuf};
use base64::{engine::general_purpose, Engine as _};
use lazy_static::lazy_static;

use crate::error::ConfigError;
use crate::{error::ConfigError, models::ResultWithDefaultError};

lazy_static! {
pub static ref TRACKED_PATH: Option<PathBuf> = locate_tracked_path().ok();
}

pub fn locate_config_path() -> Result<PathBuf, Box<dyn std::error::Error>> {
pub fn locate_config_path() -> ResultWithDefaultError<PathBuf> {
let config_root = get_config_root();

let mut config_path = std::env::current_dir()?;
let mut config_path = std::env::current_dir().expect("failed to get current directory");
let mut config_filename = get_encoded_config_path(&config_root, &config_path);

while !config_filename.exists() {
Expand All @@ -24,24 +24,24 @@ pub fn locate_config_path() -> Result<PathBuf, Box<dyn std::error::Error>> {
Ok(config_filename)
}

fn locate_tracked_path() -> Result<PathBuf, Box<dyn std::error::Error>> {
fn locate_tracked_path() -> ResultWithDefaultError<PathBuf> {
let config_root = get_config_root();

let mut config_path = std::env::current_dir()?;
let mut config_path = std::env::current_dir().expect("failed to get current directory");
let mut config_filename = get_encoded_config_path(&config_root, &config_path);

while !config_filename.exists() {
if !config_path.pop() {
return Err("No config file found".into());
panic!("No config file found");
}
config_filename = get_encoded_config_path(&config_root, &config_path);
}
Ok(config_path)
}

pub fn get_config_path_for_current_dir() -> Result<PathBuf, Box<dyn std::error::Error>> {
pub fn get_config_path_for_current_dir() -> ResultWithDefaultError<PathBuf> {
let config_root = get_config_root();
let path = std::env::current_dir()?;
let path = std::env::current_dir().expect("failed to get current directory");
Ok(get_encoded_config_path(&config_root, &path))
}

Expand Down
17 changes: 10 additions & 7 deletions src/config/manage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ impl ConfigManageCommand {
let display_path = utilities::simplify_config_path_for_display(path.as_path());

if delete {
return fs::remove_file(path).map_err(|e| e.into()).map(|_| {
println!(
"{} {}",
"Config file deleted from".red().bold(),
display_path
);
});
return {
fs::remove_file(path).map(|_| {
println!(
"{} {}",
"Config file deleted from".red().bold(),
display_path
);
}).expect("failed to delete config");
Ok(())
};
}
if edit {
return utilities::open_path_in_editor(path);
Expand Down
51 changes: 30 additions & 21 deletions src/config/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,18 +293,19 @@ fn resolve_token_to_macro(token: &str) -> Option<Macro> {
}
}

fn resolve_macro(
base_dir: &Path,
instruction: Macro,
) -> Result<String, Box<dyn std::error::Error>> {
fn resolve_macro(base_dir: &Path, instruction: Macro) -> ResultWithDefaultError<String> {
match instruction {
Macro::Branch => {
let output = std::process::Command::new("git")
.arg("rev-parse")
.arg("--abbrev-ref")
.arg("HEAD")
.output()?;
Ok(String::from_utf8(output.stdout)?.trim().to_string())
.output()
.expect("Failed to resolve branch");
Ok(String::from_utf8(output.stdout)
.expect("Failed to convert branch name to string. This should never happen.")
.trim()
.to_string())
}
Macro::BaseDir => Ok(base_dir
.file_name()
Expand All @@ -325,11 +326,11 @@ fn resolve_macro(
Ok(parent_dir)
}
Macro::CurrentDir => {
let output = env::current_dir()?;
let output = env::current_dir().expect("Failed to get current directory");
Ok(output.file_name().unwrap().to_str().unwrap().to_string())
}
Macro::ParentDir => {
let current_dir = env::current_dir()?;
let current_dir = env::current_dir().expect("Failed to get current directory");
let parent_dir_path = current_dir.parent().unwrap().to_path_buf();
Ok(parent_dir_path
.file_name()
Expand All @@ -353,24 +354,24 @@ fn resolve_macro(
)));
}
let git_root = PathBuf::from(
String::from_utf8(output.stdout).map(|s| s.trim().to_string())?,
String::from_utf8(output.stdout)
.map(|s| s.trim().to_string())
.expect(
"Failed to convert git root to string. This should never happen.",
),
);

// Check if we are in a git worktree
// If so, we need to get the root of the main repository
let git_dir = git_root.join(".git");
if git_dir.is_file() {
let git_dir = std::fs::read_to_string(git_dir)?;
let git_dir = std::fs::read_to_string(git_dir)
.expect("Failed to read git directory. No git root maybe?");

let git_dir = git_dir
.split(':')
.nth(1)
.ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::Other,
"Failed to resolve git worktree root",
)
})?
.expect("Failed to resolve git worktree root")
.trim();
let git_root = PathBuf::from(git_dir);

Expand Down Expand Up @@ -417,7 +418,10 @@ fn resolve_macro(
"Failed to resolve git root",
)));
}
let git_root = PathBuf::from(String::from_utf8(output.stdout)?);
let git_root = PathBuf::from(
String::from_utf8(output.stdout)
.expect("Failed to convert git root to string. Not in a git root?"),
);
Ok(git_root
.parent()
.unwrap()
Expand All @@ -438,10 +442,15 @@ fn resolve_macro(
if !output.status.success() {
return Err(Box::new(ConfigError::ShellResolution(
command,
String::from_utf8(output.stderr)?,
String::from_utf8(output.stderr).unwrap(),
)));
}
Ok(String::from_utf8(output.stdout)?.trim().to_string())
Ok(String::from_utf8(output.stdout)
.expect(
"Failed to convert shell output to string. This should never happen.",
)
.trim()
.to_string())
}
Err(e) => Err(Box::new(ConfigError::ShellResolution(
command,
Expand All @@ -452,7 +461,7 @@ fn resolve_macro(
}
}

fn resolve_token(base_dir: &Path, token: &str) -> Result<String, Box<dyn std::error::Error>> {
fn resolve_token(base_dir: &Path, token: &str) -> ResultWithDefaultError<String> {
match resolve_token_to_macro(token) {
Some(macro_) => resolve_macro(base_dir, macro_),
None => Err(Box::new(ConfigError::UnrecognizedMarco(token.to_string()))),
Expand Down Expand Up @@ -510,7 +519,7 @@ impl TrackConfig {
self.get_branch_config(branch.as_deref())
}
pub fn get_active_config(&self) -> ResultWithDefaultError<&BranchConfig> {
let current_dir = std::env::current_dir()?;
let current_dir = std::env::current_dir().expect("Failed to get current directory");
return Ok(self.get_branch_config_for_dir(&current_dir));
}
pub fn get_default_entry(&self, entities: Entities) -> ResultWithDefaultError<TimeEntry> {
Expand Down
10 changes: 5 additions & 5 deletions src/config/parser.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::path::Path;
use toml;

use crate::models::ResultWithDefaultError;

use super::model::TrackConfig;

pub fn get_config_from_file<P: AsRef<Path>>(
path: P,
) -> Result<TrackConfig, Box<dyn std::error::Error>> {
let contents = std::fs::read_to_string(path)?;
let config: TrackConfig = toml::from_str(&contents)?;
pub fn get_config_from_file<P: AsRef<Path>>(path: P) -> ResultWithDefaultError<TrackConfig> {
let contents = std::fs::read_to_string(path).expect("failed to read config file");
let config: TrackConfig = toml::from_str(&contents).expect("failed to parse config");

Ok(config)
}
Loading

0 comments on commit e24659e

Please sign in to comment.