tangled
alpha
login
or
join now
ngp.computer
/
tsk
A file-based task manager
0
fork
atom
overview
issues
pulls
pipelines
WIP: task stack
ngp.computer
1 year ago
11fb435b
16f3a04a
+77
-15
5 changed files
expand all
collapse all
unified
split
src
buffer.rs
main.rs
stack.rs
util.rs
workspace.rs
+51
src/buffer.rs
···
1
1
+
use std::{
2
2
+
collections::BinaryHeap,
3
3
+
sync::{Condvar, Mutex},
4
4
+
};
5
5
+
struct PooledHandle<'a, T: Ord + Default> {
6
6
+
parent: &'a Pool<T>,
7
7
+
item: Option<T>,
8
8
+
}
9
9
+
10
10
+
struct Pool<T: Ord + Default>(Mutex<BinaryHeap<T>>, Condvar);
11
11
+
12
12
+
impl<'a, T: Ord + Default> Pool<T> {
13
13
+
pub fn give(&self, item: T) {
14
14
+
self.0.lock().expect("Poisoned lock").push(item)
15
15
+
}
16
16
+
17
17
+
/// Retrieves
18
18
+
pub fn take(&self) -> Option<T> {
19
19
+
self.0.lock().expect("Poisoned lock").pop()
20
20
+
}
21
21
+
22
22
+
pub fn lease(&self) -> PooledHandle<'a, T> {
23
23
+
let guard = self.0.lock().expect("Poisoned lock");
24
24
+
match guard.pop() {
25
25
+
Some(item) => PooledHandle {
26
26
+
parent: self,
27
27
+
item: Some(item),
28
28
+
},
29
29
+
None => {
30
30
+
let mut item = None;
31
31
+
while item.is_none() {
32
32
+
let guard = self.1.wait(guard).expect("Poisoned lock");
33
33
+
item = guard.pop();
34
34
+
}
35
35
+
36
36
+
},
37
37
+
}
38
38
+
}
39
39
+
}
40
40
+
41
41
+
impl<T: Ord> AsRef<T> for PooledHandle<'_, T> {
42
42
+
fn as_ref(&self) -> &T {
43
43
+
&self.item
44
44
+
}
45
45
+
}
46
46
+
47
47
+
impl<T: Ord> Drop for PooledHandle<'_, T> {
48
48
+
fn drop(&mut self) {
49
49
+
self.parent.give(self.item)
50
50
+
}
51
51
+
}
+1
src/main.rs
···
2
2
mod workspace;
3
3
mod stack;
4
4
mod util;
5
5
+
mod buffer;
5
6
use std::path::PathBuf;
6
7
use std::{env::current_dir, io::Read};
7
8
use workspace::Workspace;
+6
-12
src/stack.rs
···
3
3
4
4
use crate::errors::{Error, Result};
5
5
use crate::util;
6
6
-
use std::io::{self, BufRead};
7
7
-
use std::num::ParseIntError;
8
8
-
use std::{fs::File, io::Read, path::PathBuf};
6
6
+
use std::io::{self, BufRead, Read};
7
7
+
use std::{fs::File, path::PathBuf};
9
8
10
9
use nix::fcntl::{Flock, FlockArg};
11
10
12
12
-
use crate::workspace::Id;
13
13
-
14
14
-
const INDEXFILE: &str = "index";
15
15
-
const TITLECACHEFILE: &str = "cache";
11
11
+
use crate::workspace::{Id, Workspace};
16
12
17
13
struct StackItem {
18
14
id: Id,
···
28
24
}
29
25
30
26
impl StackItem {
31
31
-
fn from_reader(reader: &mut impl BufRead) -> Result<Self> {
27
27
+
fn from_reader(workspace_path: &PathBuf, reader: &mut impl BufRead) -> Result<Self> {
32
28
let mut buf = String::new();
33
29
reader.read_line(&mut buf)?;
34
30
if buf.is_empty() {
···
38
34
)));
39
35
}
40
36
let (id, next) = Self::parse(&buf)?;
37
37
+
let title = util::flopen(workspace_path.join("tasks").join(id), mode)
41
38
todo!();
42
39
}
43
40
···
63
60
}
64
61
65
62
impl TaskStack {
66
66
-
fn from_tskdir(path: &PathBuf) -> Self {
67
67
-
let index = util::flopen(&path.join(INDEXFILE), FlockArg::LockExclusive);
68
68
-
let cache = util::flopen(&path.join(TITLECACHEFILE), FlockArg::LockShared);
69
69
-
63
63
+
fn from_tskdir(path: &PathBuf) -> Result<Self> {
70
64
todo!()
71
65
}
72
66
}
+1
-1
src/util.rs
···
6
6
7
7
use nix::fcntl::{Flock, FlockArg};
8
8
9
9
-
pub fn flopen(path: &PathBuf, mode: FlockArg) -> Result<Flock<File>> {
9
9
+
pub fn flopen(path: PathBuf, mode: FlockArg) -> Result<Flock<File>> {
10
10
let file = OpenOptions::new()
11
11
.read(true)
12
12
.write(true)
+18
-2
src/workspace.rs
···
2
2
use nix::fcntl::{Flock, FlockArg};
3
3
4
4
use crate::errors::{Error, Result};
5
5
+
use crate::stack::TaskStack;
5
6
use crate::util;
6
7
use std::fs::File;
7
8
use std::io::{Read, Seek};
···
9
10
use std::str::FromStr;
10
11
use std::{fs::OpenOptions, io::Write};
11
12
13
13
+
const INDEXFILE: &str = "index";
14
14
+
const TITLECACHEFILE: &str = "cache";
12
15
/// A unique identifier for a task. When referenced in text, it is prefixed with `tsk-`.
13
16
pub struct Id(u32);
14
17
···
58
61
}
59
62
60
63
pub fn next_id(&self) -> Result<Id> {
61
61
-
let mut file = util::flopen(&self.path.join("next"), FlockArg::LockExclusive)?;
64
64
+
let mut file = util::flopen(self.path.join("next"), FlockArg::LockExclusive)?;
62
65
let mut buf = String::new();
63
66
file.read_to_string(&mut buf)?;
64
67
let id = buf.trim().parse::<u32>()?;
···
75
78
// TODO: we could improperly increment the id if the task is not written to disk/errors
76
79
let id = self.next_id()?;
77
80
let mut file = util::flopen(
78
78
-
&self.path.join("tasks").join(format!("tsk-{}.tsk", id.0)),
81
81
+
self.path.join("tasks").join(format!("tsk-{}.tsk", id.0)),
79
82
FlockArg::LockExclusive,
80
83
)?;
81
84
file.write_all(format!("{title}\n\n{body}").as_bytes())?;
···
85
88
body,
86
89
file,
87
90
})
91
91
+
}
92
92
+
93
93
+
fn read_stack(&self) -> Result<TaskStack> {
94
94
+
let mut index = String::new();
95
95
+
let mut cache = String::new();
96
96
+
let mut index_file = util::flopen(self.path.join(INDEXFILE), FlockArg::LockExclusive)?;
97
97
+
let mut cache_file = util::flopen(self.path.join(TITLECACHEFILE), FlockArg::LockShared)?;
98
98
+
index_file.read_to_string(&mut index)?;
99
99
+
for line in index.lines() {
100
100
+
101
101
+
}
102
102
+
103
103
+
todo!();
88
104
}
89
105
}
90
106