Skip to content

Commit

Permalink
Merge pull request #546 from RedEtherbloom/tkw3_fix
Browse files Browse the repository at this point in the history
Switch to taskwarrior v3.X backend
  • Loading branch information
kdheepak authored May 12, 2024
2 parents cfedca0 + 0d23399 commit c3f2d06
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ jobs:
cd /tmp
git clone https://github.com/GothenburgBitFactory/taskwarrior
cd taskwarrior
git checkout v2.6.1
git checkout v3.0.0
cmake -DCMAKE_BUILD_TYPE=release -DENABLE_SYNC=OFF .
make
sudo make install
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
cd /tmp
git clone https://github.com/GothenburgBitFactory/taskwarrior
cd taskwarrior
git checkout v2.6.1
git checkout v3.0.0
cmake -DCMAKE_BUILD_TYPE=release -DENABLE_SYNC=OFF .
make
sudo make install
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

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

8 changes: 3 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "taskwarrior-tui"
version = "0.25.4"
version = "0.26.0"
license = "MIT"
description = "A Taskwarrior Terminal User Interface"
repository = "https://github.com/kdheepak/taskwarrior-tui/"
Expand All @@ -18,9 +18,7 @@ better-panic = "0.3.0"
cassowary = "0.3.0"
chrono = "0.4.26"
clap = { version = "4.4.1", features = ["derive"] }
crossterm = { version = "0.27.0", features = [
"event-stream",
] }
crossterm = { version = "0.27.0", features = ["event-stream"] }
dirs = "5.0.1"
futures = "0.3.28"
itertools = "0.11.0"
Expand Down Expand Up @@ -57,7 +55,7 @@ taskwarrior-tui = { path = "/usr/bin/taskwarrior-tui" }
[profile.release]
debug = 1
incremental = true
lto = "off"
lto = "fat"

[build-dependencies]
clap = { version = "4.4.1", features = ["derive"] }
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# `taskwarrior-tui`

> [!IMPORTANT]
> `taskwarrior-tui` is only tested with `taskwarrior` v2.x. [`taskwarrior` v3.x](https://github.com/GothenburgBitFactory/taskwarrior/releases/tag/v3.0.0) may not work as intended.
> [`taskwarrior` v3.x](https://github.com/GothenburgBitFactory/taskwarrior/releases/tag/v3.0.0) may break `taskwarrior-tui` features in unexpected ways. Please file a bug report if you encounter a bug.
[![CI](https://github.com/kdheepak/taskwarrior-tui/workflows/CI/badge.svg)](https://github.com/kdheepak/taskwarrior-tui/actions?query=workflow%3ACI)
[![](https://img.shields.io/github/license/kdheepak/taskwarrior-tui)](./LICENSE)
Expand Down
85 changes: 48 additions & 37 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const MAX_LINE: usize = 4096;

lazy_static! {
static ref START_TIME: Instant = Instant::now();
static ref TASKWARRIOR_VERSION_SUPPORTED: Versioning = Versioning::new("2.6.0").unwrap();
static ref TASKWARRIOR_VERSION_SUPPORTED: Versioning = Versioning::new("3.0.0").unwrap();
}

#[derive(Debug)]
Expand Down Expand Up @@ -1304,12 +1304,11 @@ impl TaskwarriorTui {
self.get_context()?;
let task_uuids = self.selected_task_uuids();
if self.current_selection_uuid.is_none() && self.current_selection_id.is_none() && task_uuids.len() == 1 {
if let Some(uuid) = task_uuids.get(0) {
if let Some(uuid) = task_uuids.first() {
self.current_selection_uuid = Some(*uuid);
}
}

self.last_export = Some(std::time::SystemTime::now());
self.task_report_table.export_headers(None, &self.report)?;
self.export_tasks()?;
if self.config.uda_task_report_use_all_tasks_for_completion {
Expand All @@ -1321,6 +1320,10 @@ impl TaskwarriorTui {
self.task_details.clear();
self.dirty = false;
self.save_history()?;

// Some operations like export or summary change the taskwarrior database.
// The export time therefore gets set at the end, to avoid an infinite update loop.
self.last_export = Some(std::time::SystemTime::now());
}
self.cursor_fix();
self.update_task_table_state();
Expand Down Expand Up @@ -1608,20 +1611,21 @@ impl TaskwarriorTui {
}
}

fn get_task_files_max_mtime(&self) -> Result<SystemTime> {
let data_dir = shellexpand::tilde(&self.config.data_location).into_owned();
["backlog.data", "completed.data", "pending.data"]
.iter()
.map(|n| fs::metadata(Path::new(&data_dir).join(n)).map(|m| m.modified()))
.filter_map(Result::ok)
.filter_map(Result::ok)
.max()
.ok_or_else(|| anyhow!("Unable to get task files max time"))
fn get_task_database_mtime(&self) -> Result<SystemTime> {
let data_dir = shellexpand::tilde(&self.config.data_location);
let database_path = Path::new(data_dir.as_ref()).join("taskchampion.sqlite3");

let metadata = fs::metadata(database_path).context("Fetching the metadate of the task database failed")?;
let mtime = metadata
.modified()
.context("Could not get mtime of task database, but fetching metadata succeeded")?;

Ok(mtime)
}

pub fn tasks_changed_since(&mut self, prev: Option<SystemTime>) -> Result<bool> {
if let Some(prev) = prev {
let mtime = self.get_task_files_max_mtime()?;
let mtime = self.get_task_database_mtime()?;
if mtime > prev {
Ok(true)
} else {
Expand Down Expand Up @@ -1794,7 +1798,7 @@ impl TaskwarriorTui {
};

if task_uuids.len() == 1 {
if let Some(uuid) = task_uuids.get(0) {
if let Some(uuid) = task_uuids.first() {
self.current_selection_uuid = Some(*uuid);
}
}
Expand Down Expand Up @@ -1904,7 +1908,7 @@ impl TaskwarriorTui {
};

if task_uuids.len() == 1 {
if let Some(uuid) = task_uuids.get(0) {
if let Some(uuid) = task_uuids.first() {
self.current_selection_uuid = Some(*uuid);
}
}
Expand Down Expand Up @@ -1957,7 +1961,7 @@ impl TaskwarriorTui {
};

if task_uuids.len() == 1 {
if let Some(uuid) = task_uuids.get(0) {
if let Some(uuid) = task_uuids.first() {
self.current_selection_uuid = Some(*uuid);
}
}
Expand Down Expand Up @@ -2009,7 +2013,7 @@ impl TaskwarriorTui {
};

if task_uuids.len() == 1 {
if let Some(uuid) = task_uuids.get(0) {
if let Some(uuid) = task_uuids.first() {
self.current_selection_uuid = Some(*uuid);
}
}
Expand Down Expand Up @@ -2096,7 +2100,7 @@ impl TaskwarriorTui {
}

if task_uuids.len() == 1 {
if let Some(uuid) = task_uuids.get(0) {
if let Some(uuid) = task_uuids.first() {
self.current_selection_uuid = Some(*uuid);
}
}
Expand Down Expand Up @@ -2136,7 +2140,7 @@ impl TaskwarriorTui {
}

if task_uuids.len() == 1 {
if let Some(uuid) = task_uuids.get(0) {
if let Some(uuid) = task_uuids.first() {
self.current_selection_uuid = Some(*uuid);
}
}
Expand Down Expand Up @@ -3763,13 +3767,28 @@ pub fn remove_tag(task: &mut Task, tag: &str) {
}

#[cfg(test)]
// Disabled, as "'" should be a String for more readable shlex shell escaping.
#[allow(clippy::single_char_pattern)]
mod tests {
use std::{ffi::OsStr, fmt::Write, fs::File, io, path::Path};
use std::{
ffi::OsStr,
fmt::Write,
fs::File,
io,
path::{Path, PathBuf},
};

use ratatui::{backend::TestBackend, buffer::Buffer};

use super::*;

fn get_taskdata_path() -> PathBuf {
let taskdata_env_var = std::env::var("TASKDATA").expect("TASKDATA environment variable not set.");
let taskdata_path = Path::new(&taskdata_env_var).to_owned();

taskdata_path
}

/// Returns a string representation of the given buffer for debugging purpose.
fn buffer_view(buffer: &Buffer) -> String {
let mut view = String::with_capacity(buffer.content.len() + buffer.area.height as usize * 3);
Expand Down Expand Up @@ -3801,7 +3820,7 @@ mod tests {

fn setup() {
use std::process::Stdio;
let mut f = File::open(Path::new(env!("TASKDATA")).parent().unwrap().join("export.json")).unwrap();
let mut f = File::open(get_taskdata_path().parent().unwrap().join("export.json")).unwrap();
let mut s = String::new();
f.read_to_string(&mut s).unwrap();
let tasks = task_hookrs::import::import(s.as_bytes()).unwrap();
Expand All @@ -3812,7 +3831,7 @@ mod tests {
}

fn teardown() {
let cd = Path::new(env!("TASKDATA"));
let cd = get_taskdata_path();
std::fs::remove_dir_all(cd).unwrap();
}

Expand Down Expand Up @@ -3892,24 +3911,16 @@ mod tests {
// teardown();
}

#[test]
fn test_taskwarrior_tui() {
let r = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap()
.block_on(async { _test_taskwarrior_tui().await });
}

async fn _test_taskwarrior_tui() {
#[tokio::test]
async fn test_taskwarrior_tui() {
let app = TaskwarriorTui::new("next", false).await.unwrap();

assert!(
app.task_by_index(0).is_none(),
"Expected task data to be empty but found {} tasks. Delete contents of {:?} and {:?} and run the tests again.",
app.tasks.len(),
Path::new(env!("TASKDATA")),
Path::new(env!("TASKDATA")).parent().unwrap().join(".config")
get_taskdata_path(),
get_taskdata_path().parent().unwrap().join(".config")
);

let app = TaskwarriorTui::new("next", false).await.unwrap();
Expand Down Expand Up @@ -3958,7 +3969,7 @@ mod tests {

let mut app = TaskwarriorTui::new("next", false).await.unwrap();
let task = app.task_by_id(11).unwrap();
let tags = vec!["finance", "UNBLOCKED", "PENDING", "TAGGED", "UDA"]
let tags = ["finance", "UNBLOCKED", "PENDING", "TAGGED", "UDA"]
.iter()
.map(ToString::to_string)
.collect::<Vec<String>>();
Expand All @@ -3977,7 +3988,7 @@ mod tests {
app.update(true).await.unwrap();

let task = app.task_by_id(11).unwrap();
let tags = vec!["next", "finance", "UNBLOCKED", "PENDING", "TAGGED", "UDA"]
let tags = ["next", "finance", "UNBLOCKED", "PENDING", "TAGGED", "UDA"]
.iter()
.map(ToString::to_string)
.collect::<Vec<String>>();
Expand All @@ -3989,7 +4000,7 @@ mod tests {
app.update(true).await.unwrap();

let task = app.task_by_id(11).unwrap();
let tags = vec!["finance", "UNBLOCKED", "PENDING", "TAGGED", "UDA"]
let tags = ["finance", "UNBLOCKED", "PENDING", "TAGGED", "UDA"]
.iter()
.map(ToString::to_string)
.collect::<Vec<String>>();
Expand Down
5 changes: 2 additions & 3 deletions src/calendar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ impl<'a> Widget for Calendar<'a> {

impl<'a> Calendar<'a> {
fn generate_month_names() -> [&'a str; 12] {
let month_names = [
[
Month::January.name(),
Month::February.name(),
Month::March.name(),
Expand All @@ -262,7 +262,6 @@ impl<'a> Calendar<'a> {
Month::October.name(),
Month::November.name(),
Month::December.name(),
];
month_names
]
}
}

0 comments on commit c3f2d06

Please sign in to comment.