Skip to content

Commit

Permalink
Separate ThreeDirInput and FakeData
Browse files Browse the repository at this point in the history
  • Loading branch information
ilyagr committed Mar 10, 2024
1 parent 2f935ff commit 9037335
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 129 deletions.
2 changes: 1 addition & 1 deletion backend-local-server/src/bin/diffedit3-web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn exit_with_cli_error(s: String) -> ! {
#[tokio::main]
async fn main() -> Result<(), MergeToolError> {
let cli = LocalServerCli::parse();
let input: diffedit3::fs::ThreeDirInput = match cli.lib_cli.try_into() {
let input: Box<dyn diffedit3::DataInterface> = match cli.lib_cli.into_data_interface() {
Ok(i) => i,
Err(err) => {
exit_with_cli_error(err.to_string());
Expand Down
117 changes: 23 additions & 94 deletions backend-local-server/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,28 @@ use std::path::{Path, PathBuf};

use walkdir::{DirEntry, WalkDir};

use crate::{DataInterface, DataReadError, DataSaveError, EntriesToCompare, FileEntry};

fn scan(root: &Path) -> impl Iterator<Item = Result<(DirEntry, String), DataReadError>> {
// As an alternative to WalkDir, see
// https://github.com/martinvonz/jj/blob/af8eb3fd74956effee00acf00011ff0413607213/lib/src/local_working_copy.rs#L849
WalkDir::new(root)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.file_type().is_file())
.map(|e| Ok((e.clone(), std::fs::read_to_string(e.path())?)))
}
use crate::{DataInterface, DataReadError, DataSaveError, EntriesToCompare, FakeData, FileEntry};

#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum ThreeDirInput {
// TODO: Separate FakeData
FakeData,
Dirs {
left: PathBuf,
right: PathBuf,
edit: PathBuf,
},
pub struct ThreeDirInput {
left: PathBuf,
right: PathBuf,
edit: PathBuf,
}

impl DataInterface for ThreeDirInput {
// TODO: A more efficient `get_valid_entries` implementation

fn scan(&self) -> Result<EntriesToCompare, DataReadError> {
match self {
Self::FakeData => Ok(fake_data()),
Self::Dirs { left, right, edit } => scan_several([left, right, edit]),
}
let Self { left, right, edit } = self;
scan_several([left, right, edit])
}

fn save_unchecked(
&mut self,
result: indexmap::IndexMap<String, String>,
) -> Result<(), DataSaveError> {
let outdir = match self {
Self::FakeData => {
eprintln!("Can't save fake demo data. Here it is as TOML");
eprintln!();
eprintln!(
"{}",
toml::to_string(&result)
.unwrap_or_else(|err| format!("Failed to parse TOML: {err}"))
);
return Err(DataSaveError::CannotSaveFakeData);
}
Self::Dirs { edit, .. } => edit,
};

let Self { edit: outdir, .. } = self;
for (relpath, contents) in result.into_iter() {
let relpath = PathBuf::from(relpath);
let path = outdir.join(relpath);
Expand Down Expand Up @@ -81,23 +52,22 @@ pub struct Cli {
demo: bool,
}

impl TryInto<ThreeDirInput> for Cli {
type Error = String;
fn try_into(self) -> Result<ThreeDirInput, Self::Error> {
impl Cli {
pub fn into_data_interface(self) -> Result<Box<dyn DataInterface>, String> {
if self.demo {
Ok(ThreeDirInput::FakeData)
Ok(Box::new(FakeData))
} else {
match self.dirs.as_slice() {
[left, right, output] => Ok(ThreeDirInput::Dirs {
[left, right, output] => Ok(Box::new(ThreeDirInput {
left: left.to_path_buf(),
right: right.to_path_buf(),
edit: output.to_path_buf(),
}),
[left, right] => Ok(ThreeDirInput::Dirs {
})),
[left, right] => Ok(Box::new(ThreeDirInput {
left: left.to_path_buf(),
right: right.to_path_buf(),
edit: right.to_path_buf(),
}),
})),
_ => Err(format!(
"Must have 2 or 3 dirs to compare, got {} dirs instead",
self.dirs.len()
Expand All @@ -107,55 +77,14 @@ impl TryInto<ThreeDirInput> for Cli {
}
}

pub fn fake_data() -> EntriesToCompare {
// let mut two_sides_map = btreemap! {
// "edited_file" => [
// Some("First\nThird\nFourth\nFourthAndAHalf\n\nFifth\nSixth\n----\
// none two"), Some("First\nSecond\nThird\nFifth\nSixth\n----\
// none\n") ],
// "deleted_file" => [Some("deleted"), None],
// "added file" => [None, Some("added")]
// };
let two_sides_map = vec![
(
"edited_file",
[
FileEntry::Text(
"First\nThird\nFourth\nFourthAndAHalf\n\nFifth\nSixth\n----\none two"
.to_string(),
),
FileEntry::Text("First\nSecond\nThird\nFifth\nSixth\n----\none\n".to_string()),
],
),
(
"deleted_file",
[FileEntry::Text("deleted".to_string()), FileEntry::Missing],
),
(
"added file",
[FileEntry::Missing, FileEntry::Text("added".to_string())],
),
(
"unsupported-left",
[
FileEntry::Unsupported("demo of an unsupported file".to_string()),
FileEntry::Text("text".to_string()),
],
),
(
"unsupported-right",
[
FileEntry::Text("text".to_string()),
FileEntry::Unsupported("demo of an unsupported file".to_string()),
],
),
];
EntriesToCompare(
two_sides_map
.into_iter()
.map(|(key, [left, right])| (PathBuf::from(key), [left, right.clone(), right]))
.collect(),
)
fn scan(root: &Path) -> impl Iterator<Item = Result<(DirEntry, String), DataReadError>> {
// As an alternative to WalkDir, see
// https://github.com/martinvonz/jj/blob/af8eb3fd74956effee00acf00011ff0413607213/lib/src/local_working_copy.rs#L849
WalkDir::new(root)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.file_type().is_file())
.map(|e| Ok((e.clone(), std::fs::read_to_string(e.path())?)))
}

// pub fn scan_several<const N: usize>(roots: [&Path; N]) ->
Expand Down
27 changes: 1 addition & 26 deletions backend-local-server/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,6 @@
pub mod fs;
pub mod types;
pub mod local_server;
pub mod types;

pub use fs::{Cli, ThreeDirInput};
pub use types::*;

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn it_works() {
insta::assert_yaml_snapshot!(ThreeDirInput::FakeData.scan().unwrap(),
@r###"
---
added file:
- ~
- added
- added
deleted_file:
- deleted
- ~
- ~
edited_file:
- "First\nThird\nFourth\nFourthAndAHalf\n\nFifth\nSixth\n----\none two"
- "First\nSecond\nThird\nFifth\nSixth\n----\none\n"
- "First\nSecond\nThird\nFifth\nSixth\n----\none\n"
"###);
}
}
4 changes: 2 additions & 2 deletions backend-local-server/src/local_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use poem::{handler, EndpointExt, Result, Route, Server};
use thiserror::Error;

use crate::DataInterface;
type DataInterfacePointer = Arc<Mutex<dyn DataInterface>>;
type DataInterfacePointer = Arc<Mutex<Box<dyn DataInterface>>>;

#[derive(rust_embed::RustEmbed)]
#[folder = "../webapp/dist"]
Expand Down Expand Up @@ -130,7 +130,7 @@ fn acceptor_to_socket_address(
}

pub async fn run_server(
input: impl crate::DataInterface,
input: Box<dyn crate::DataInterface>,
min_port: usize,
max_port: usize,
open_browser: bool,
Expand Down
93 changes: 93 additions & 0 deletions backend-local-server/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,96 @@ impl DataInterface for EntriesToCompare {
Ok(())
}
}

pub struct FakeData;

impl DataInterface for FakeData {
fn scan(&self) -> Result<EntriesToCompare, DataReadError> {
// let mut two_sides_map = btreemap! {
// "edited_file" => [
// Some("First\nThird\nFourth\nFourthAndAHalf\n\nFifth\nSixth\n----\
// none two"), Some("First\nSecond\nThird\nFifth\nSixth\n----\
// none\n") ],
// "deleted_file" => [Some("deleted"), None],
// "added file" => [None, Some("added")]
// };
let two_sides_map = vec![
(
"edited_file",
[
FileEntry::Text(
"First\nThird\nFourth\nFourthAndAHalf\n\nFifth\nSixth\n----\none two"
.to_string(),
),
FileEntry::Text("First\nSecond\nThird\nFifth\nSixth\n----\none\n".to_string()),
],
),
(
"deleted_file",
[FileEntry::Text("deleted".to_string()), FileEntry::Missing],
),
(
"added file",
[FileEntry::Missing, FileEntry::Text("added".to_string())],
),
(
"unsupported-left",
[
FileEntry::Unsupported("demo of an unsupported file".to_string()),
FileEntry::Text("text".to_string()),
],
),
(
"unsupported-right",
[
FileEntry::Text("text".to_string()),
FileEntry::Unsupported("demo of an unsupported file".to_string()),
],
),
];
Ok(EntriesToCompare(
two_sides_map
.into_iter()
.map(|(key, [left, right])| (PathBuf::from(key), [left, right.clone(), right]))
.collect(),
))
}

fn save_unchecked(
&mut self,
result: indexmap::IndexMap<String, String>,
) -> Result<(), DataSaveError> {
eprintln!("Can't save fake demo data. Here it is as TOML");
eprintln!();
eprintln!(
"{}",
toml::to_string(&result).unwrap_or_else(|err| format!("Failed to parse TOML: {err}"))
);
Err(DataSaveError::CannotSaveFakeData)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn it_works() {
insta::assert_yaml_snapshot!(FakeData.scan().unwrap(),
@r###"
---
added file:
- ~
- added
- added
deleted_file:
- deleted
- ~
- ~
edited_file:
- "First\nThird\nFourth\nFourthAndAHalf\n\nFifth\nSixth\n----\none two"
- "First\nSecond\nThird\nFifth\nSixth\n----\none\n"
- "First\nSecond\nThird\nFifth\nSixth\n----\none\n"
"###);
}
}
13 changes: 7 additions & 6 deletions backend-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
// #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use clap::Parser;
use diffedit3::{DataInterface, ThreeDirInput};
use diffedit3::DataInterface;
use indexmap::IndexMap;
// Using parking_lot::Mutex for a timeout. We could alternatively use
// tokio::sync::Mutex, but the docs suggest only using it if absolutely
// neccessary.
use parking_lot::Mutex;
use tauri::{CustomMenuItem, Menu, Submenu};

type DataMutex = Mutex<ThreeDirInput>;
type DataMutex = Mutex<Box<dyn DataInterface>>;

#[tauri::command]
fn args() -> Vec<String> {
Expand Down Expand Up @@ -53,10 +53,11 @@ fn get_merge_data(
// CSS property
fn main() {
let cli = diffedit3::Cli::parse();
let input: diffedit3::ThreeDirInput = cli.try_into().unwrap_or_else(|err| {
eprintln!("Error: {err}");
std::process::exit(2)
});
let input: Box<dyn diffedit3::DataInterface> =
cli.into_data_interface().unwrap_or_else(|err| {
eprintln!("Error: {err}");
std::process::exit(2)
});
let input_mutex: DataMutex = Mutex::new(input);

let abandon_changes_and_quit = CustomMenuItem::new(
Expand Down

0 comments on commit 9037335

Please sign in to comment.