aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuben Beltran del Rio <git@r.bdr.sh>2024-02-25 22:06:19 +0000
committerRuben Beltran del Rio <git@r.bdr.sh>2024-02-25 22:06:19 +0000
commita9c6be4162bd15bd41ba3605127b56cb1eb32f32 (patch)
tree6d97b0c6286b1eabb2ef5cab34b472f1622584e5 /src
parent53812065cf124b6c1bc40fceec46f8c161033e29 (diff)
Add part of the implementation for add
Diffstat (limited to 'src')
-rw-r--r--src/command/add.rs42
-rw-r--r--src/command/add_remote.rs3
-rw-r--r--src/command/generate.rs3
-rw-r--r--src/command/help.rs3
-rw-r--r--src/command/mod.rs4
-rw-r--r--src/command/publish.rs3
-rw-r--r--src/command/publish_archive.rs3
-rw-r--r--src/command/remove_remote.rs3
-rw-r--r--src/command/status/configuration_status.rs25
-rw-r--r--src/command/status/mod.rs7
-rw-r--r--src/command/sync_down.rs18
-rw-r--r--src/command/sync_up.rs3
-rw-r--r--src/command/update.rs38
-rw-r--r--src/command/version.rs3
-rw-r--r--src/constants.rs1
-rw-r--r--src/main.rs8
-rw-r--r--src/metadata.rs70
17 files changed, 199 insertions, 38 deletions
diff --git a/src/command/add.rs b/src/command/add.rs
index bc1bea0..3e0e987 100644
--- a/src/command/add.rs
+++ b/src/command/add.rs
@@ -1,10 +1,12 @@
-use std::io::Result;
+use std::fs::{create_dir_all, remove_dir_all, rename};
+use std::io::{Result, Error};
use super::{
generate::Generate,
sync_down::SyncDown,
sync_up::SyncUp,
update::Update
};
+use crate::configuration::Configuration;
pub struct Add;
@@ -12,6 +14,24 @@ impl Add {
pub fn new() -> Self {
Add
}
+
+ // moves posts to their next
+ fn shift(&self, configuration: &Configuration) -> Result<()> {
+ for i in (0..configuration.max_posts).rev() {
+ let source = configuration.posts_directory.join(i.to_string());
+ let target = configuration.posts_directory.join((i + 1).to_string());
+
+ println!("Moving {} source to {}", source.display(), target.display());
+
+ if source.exists() {
+ match rename(&source, &target) {
+ Ok(_) => continue,
+ Err(e) => return Err(Error::new(e.kind(), format!("Could not shift post {} to {}", source.display(), target.display())))
+ }
+ }
+ }
+ Ok(())
+ }
}
impl super::Command for Add {
@@ -19,9 +39,23 @@ impl super::Command for Add {
vec![Box::new(SyncDown::new())]
}
- fn execute(&self, input: Option<&String>) -> Result<()> {
- println!("Add: {:?}!", input);
- return Ok(())
+ fn execute(&self, _: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> {
+ match create_dir_all(&configuration.posts_directory) {
+ Ok(_) => {
+ match self.shift(configuration) {
+ Ok(_) => {
+ let first_directory = configuration.posts_directory.join("0");
+ let _ = remove_dir_all(&first_directory);
+ match create_dir_all(&configuration.posts_directory) {
+ Ok(_) => Ok(()),
+ Err(e) => Err(Error::new(e.kind(), format!("Could not create first post directory")))
+ }
+ },
+ Err(e) => Err(e)
+ }
+ },
+ Err(e) => Err(Error::new(e.kind(), format!("Could not create posts directory")))
+ }
}
fn after_dependencies(&self) -> Vec<Box<dyn super::Command>> {
diff --git a/src/command/add_remote.rs b/src/command/add_remote.rs
index 3d90103..c98330f 100644
--- a/src/command/add_remote.rs
+++ b/src/command/add_remote.rs
@@ -1,4 +1,5 @@
use std::io::Result;
+use crate::configuration::Configuration;
pub struct AddRemote;
@@ -13,7 +14,7 @@ impl super::Command for AddRemote {
vec![]
}
- fn execute(&self, input: Option<&String>) -> Result<()> {
+ fn execute(&self, input: Option<&String>, _: &Configuration, _: &String) -> Result<()> {
println!("Add Remote: {:?}!", input);
return Ok(())
}
diff --git a/src/command/generate.rs b/src/command/generate.rs
index 59babd5..fac73ff 100644
--- a/src/command/generate.rs
+++ b/src/command/generate.rs
@@ -1,4 +1,5 @@
use std::io::Result;
+use crate::configuration::Configuration;
pub struct Generate;
@@ -13,7 +14,7 @@ impl super::Command for Generate {
vec![]
}
- fn execute(&self, input: Option<&String>) -> Result<()> {
+ fn execute(&self, input: Option<&String>, _: &Configuration, _: &String) -> Result<()> {
println!("GENERATE! {:?}", input);
return Ok(())
}
diff --git a/src/command/help.rs b/src/command/help.rs
index 7ddcba8..8d2a2c0 100644
--- a/src/command/help.rs
+++ b/src/command/help.rs
@@ -1,5 +1,6 @@
use std::io::Result;
use super::available_commands;
+use crate::configuration::Configuration;
pub struct Help;
@@ -14,7 +15,7 @@ impl super::Command for Help {
vec![]
}
- fn execute(&self, _: Option<&String>) -> Result<()> {
+ fn execute(&self, _: Option<&String>, _: &Configuration, _: &String) -> Result<()> {
let commands = available_commands();
println!("Usage:");
println!("");
diff --git a/src/command/mod.rs b/src/command/mod.rs
index 211b10f..0c96e6f 100644
--- a/src/command/mod.rs
+++ b/src/command/mod.rs
@@ -27,9 +27,11 @@ use version::Version;
use status::Status;
use help::Help;
+use crate::configuration::Configuration;
+
pub trait Command {
fn before_dependencies(&self) -> Vec<Box<dyn Command>>;
- fn execute(&self, input: Option<&String>) -> Result<()>;
+ fn execute(&self, input: Option<&String>, configuration: &Configuration, command: &String) -> Result<()>;
fn after_dependencies(&self) -> Vec<Box<dyn Command>>;
fn command(&self) -> &'static str;
fn help(&self) -> &'static str;
diff --git a/src/command/publish.rs b/src/command/publish.rs
index d6116a4..881c987 100644
--- a/src/command/publish.rs
+++ b/src/command/publish.rs
@@ -1,4 +1,5 @@
use std::io::Result;
+use crate::configuration::Configuration;
pub struct Publish;
@@ -13,7 +14,7 @@ impl super::Command for Publish {
vec![]
}
- fn execute(&self, input: Option<&String>) -> Result<()> {
+ fn execute(&self, input: Option<&String>, _: &Configuration, _: &String) -> Result<()> {
println!("Publish: {:?}!", input);
return Ok(())
}
diff --git a/src/command/publish_archive.rs b/src/command/publish_archive.rs
index 6b98b1a..f5f114a 100644
--- a/src/command/publish_archive.rs
+++ b/src/command/publish_archive.rs
@@ -1,4 +1,5 @@
use std::io::Result;
+use crate::configuration::Configuration;
pub struct PublishArchive;
@@ -13,7 +14,7 @@ impl super::Command for PublishArchive {
vec![]
}
- fn execute(&self, input: Option<&String>) -> Result<()> {
+ fn execute(&self, input: Option<&String>, _: &Configuration, _: &String) -> Result<()> {
println!("Publish Archive: {:?}!", input);
return Ok(())
}
diff --git a/src/command/remove_remote.rs b/src/command/remove_remote.rs
index cfc5cdb..8188beb 100644
--- a/src/command/remove_remote.rs
+++ b/src/command/remove_remote.rs
@@ -1,4 +1,5 @@
use std::io::Result;
+use crate::configuration::Configuration;
pub struct RemoveRemote;
@@ -13,7 +14,7 @@ impl super::Command for RemoveRemote {
vec![]
}
- fn execute(&self, input: Option<&String>) -> Result<()> {
+ fn execute(&self, input: Option<&String>, _: &Configuration, _: &String) -> Result<()> {
println!("Remove Remote: {:?}!", input);
return Ok(())
}
diff --git a/src/command/status/configuration_status.rs b/src/command/status/configuration_status.rs
index 67bf277..6d4e56a 100644
--- a/src/command/status/configuration_status.rs
+++ b/src/command/status/configuration_status.rs
@@ -2,36 +2,35 @@ use std::fs;
use std::path::PathBuf;
use crate::configuration::Configuration;
-pub fn status() -> String {
- let configuration = Configuration::new();
+pub fn status(configuration: &Configuration) -> String {
let mut status_message = String::new();
status_message.push_str("# Configuration\n");
- status_message.push_str("## Directories\n");
+ status_message.push_str("\n## Directories\n");
// Main Configuration Locations
- status_message.push_str(&get_directory_stats("Configuration", configuration.config_directory));
- status_message.push_str(&get_directory_stats("Data", configuration.data_directory));
- status_message.push_str(&get_directory_stats("Output", configuration.output_directory));
+ status_message.push_str(&get_directory_stats("Configuration", &configuration.config_directory));
+ status_message.push_str(&get_directory_stats("Data", &configuration.data_directory));
+ status_message.push_str(&get_directory_stats("Output", &configuration.output_directory));
- status_message.push_str("## Blog Settings\n");
+ status_message.push_str("\n## Blog Settings\n");
status_message.push_str(&format!("Number of posts to keep: {}\n", configuration.max_posts));
status_message
}
-fn get_directory_stats(label: &str, directory: PathBuf) -> String {
+fn get_directory_stats(label: &str, directory: &PathBuf) -> String {
let mut status_message = String::new();
- status_message.push_str(&format!("{}: {}\n", label, directory.display()));
+ status_message.push_str(&format!("{}: {}. ", label, directory.display()));
if directory.exists() {
- status_message.push_str(&format!("{} directory exists.\n", label));
+ status_message.push_str("Exists ");
if fs::read_dir(&directory).is_ok() {
- status_message.push_str(&format!("{} directory is readable.\n", label));
+ status_message.push_str("and is readable.\n");
} else {
- status_message.push_str(&format!("{} directory is not readable.\n", label));
+ status_message.push_str("but is not readable.\n");
}
} else {
- status_message.push_str(&format!("{} directory does not exist.\n", label));
+ status_message.push_str("Does not exist.\n");
}
status_message
diff --git a/src/command/status/mod.rs b/src/command/status/mod.rs
index ba73184..e8754f5 100644
--- a/src/command/status/mod.rs
+++ b/src/command/status/mod.rs
@@ -1,6 +1,7 @@
mod configuration_status;
use std::io::Result;
+use crate::configuration::Configuration;
pub struct Status;
@@ -15,10 +16,10 @@ impl super::Command for Status {
vec![]
}
- fn execute(&self, _: Option<&String>) -> Result<()> {
+ fn execute(&self, _: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> {
let status_providers = available_status_providers();
for status_provider in status_providers {
- println!("{}", status_provider());
+ println!("{}", status_provider(configuration));
}
return Ok(())
}
@@ -36,7 +37,7 @@ impl super::Command for Status {
}
}
-fn available_status_providers() -> Vec<fn() -> String> {
+fn available_status_providers() -> Vec<fn(&Configuration) -> String> {
vec![
configuration_status::status,
]
diff --git a/src/command/sync_down.rs b/src/command/sync_down.rs
index c00b01a..dc4114e 100644
--- a/src/command/sync_down.rs
+++ b/src/command/sync_down.rs
@@ -1,4 +1,6 @@
-use std::io::Result;
+use std::fs::create_dir_all;
+use std::io::{Result, Error};
+use crate::configuration::Configuration;
pub struct SyncDown;
@@ -13,9 +15,17 @@ impl super::Command for SyncDown {
vec![]
}
- fn execute(&self, input: Option<&String>) -> Result<()> {
- println!("Sync Down: {:?}!", input);
- return Ok(())
+ fn execute(&self, _: Option<&String>, configuration: &Configuration, command: &String) -> Result<()> {
+ match create_dir_all(&configuration.data_directory) {
+ Ok(_) => {
+ // We only care to show these warnings if this is the primary command.
+ if command == self.command() {
+ println!("WARNING: Sync Down Not yet implemented");
+ }
+ return Ok(())
+ },
+ Err(e) => Err(Error::new(e.kind(), format!("Could not create data directory")))
+ }
}
fn after_dependencies(&self) -> Vec<Box<dyn super::Command>> {
diff --git a/src/command/sync_up.rs b/src/command/sync_up.rs
index d35ce7f..635de10 100644
--- a/src/command/sync_up.rs
+++ b/src/command/sync_up.rs
@@ -1,4 +1,5 @@
use std::io::Result;
+use crate::configuration::Configuration;
pub struct SyncUp;
@@ -13,7 +14,7 @@ impl super::Command for SyncUp {
vec![]
}
- fn execute(&self, input: Option<&String>) -> Result<()> {
+ fn execute(&self, input: Option<&String>, _: &Configuration, _: &String) -> Result<()> {
println!("Sync Up: {:?}!", input);
return Ok(())
}
diff --git a/src/command/update.rs b/src/command/update.rs
index 0a0211c..ed6b066 100644
--- a/src/command/update.rs
+++ b/src/command/update.rs
@@ -1,5 +1,10 @@
-use std::io::Result;
+use std::fs::create_dir_all;
+use std::io::{Result, Error, ErrorKind};
+use std::path::PathBuf;
use super::{sync_down::SyncDown, generate::Generate, sync_up::SyncUp};
+use crate::configuration::Configuration;
+use crate::constants::METADATA_FILENAME;
+use crate::metadata::Metadata;
pub struct Update;
@@ -7,6 +12,18 @@ impl Update {
pub fn new() -> Self {
Update
}
+
+ fn copy_post(&self, post_location: &PathBuf) {
+
+ }
+
+ fn write_metadata(&self, metadata: Metadata, metadata_location: &PathBuf) {
+
+ }
+
+ fn archive(&self, post_location: &PathBuf) {
+
+ }
}
impl super::Command for Update {
@@ -14,8 +31,23 @@ impl super::Command for Update {
vec![Box::new(SyncDown::new())]
}
- fn execute(&self, input: Option<&String>) -> Result<()> {
- println!("Update: {:?}!", input);
+ fn execute(&self, input: Option<&String>, configuration: &Configuration, _: &String) -> Result<()> {
+ let input = input.expect("You must provide a path to a post");
+ let post_location = PathBuf::from(input);
+ if !post_location.exists() {
+ return Err(Error::new(ErrorKind::NotFound, "The path provided does not exist"));
+ }
+
+ create_dir_all(&configuration.posts_directory)?;
+
+ let metadata_file_path = configuration.posts_directory
+ .join("0")
+ .join(METADATA_FILENAME);
+ let metadata = Metadata::read_or_create(&metadata_file_path);
+
+ self.copy_post(&post_location);
+ self.write_metadata(metadata, &metadata_file_path);
+ self.archive(&post_location);
return Ok(())
}
diff --git a/src/command/version.rs b/src/command/version.rs
index a8b970b..e566c5a 100644
--- a/src/command/version.rs
+++ b/src/command/version.rs
@@ -1,4 +1,5 @@
use std::io::Result;
+use crate::configuration::Configuration;
pub struct Version;
@@ -13,7 +14,7 @@ impl super::Command for Version {
vec![]
}
- fn execute(&self, _: Option<&String>) -> Result<()> {
+ fn execute(&self, _: Option<&String>, _: &Configuration, _: &String) -> Result<()> {
let version = env!("CARGO_PKG_VERSION");
println!("{}", version);
return Ok(())
diff --git a/src/constants.rs b/src/constants.rs
new file mode 100644
index 0000000..4519426
--- /dev/null
+++ b/src/constants.rs
@@ -0,0 +1 @@
+pub const METADATA_FILENAME: &str = "metadata.json";
diff --git a/src/main.rs b/src/main.rs
index bf1e184..4cb8036 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,13 +1,17 @@
// mod argument_parser;
mod configuration;
mod command;
+mod constants;
+mod metadata;
use std::iter::once;
use std::env::args;
use std::io::Result;
use command::{available_commands, Command, help::Help};
+use configuration::Configuration;
fn main() -> Result<()> {
+ let configuration = Configuration::new();
let commands = available_commands();
let arguments: Vec<String> = args().collect();
@@ -23,7 +27,7 @@ fn main() -> Result<()> {
.collect();
for command in command_chain {
- let result = command.execute(arguments.get(2));
+ let result = command.execute(arguments.get(2), &configuration, command_name);
if let Err(_) = result {
return result;
}
@@ -33,5 +37,5 @@ fn main() -> Result<()> {
}
}
- Help::new().execute(None)
+ Help::new().execute(None, &configuration, &"help".to_string())
}
diff --git a/src/metadata.rs b/src/metadata.rs
new file mode 100644
index 0000000..97ef0d3
--- /dev/null
+++ b/src/metadata.rs
@@ -0,0 +1,70 @@
+use std::fs::File;
+use std::path::PathBuf;
+use std::io::Read;
+use std::time::{SystemTime, UNIX_EPOCH};
+
+pub struct Metadata {
+ pub id: String,
+ pub created_on: u128
+}
+
+impl Metadata {
+ pub fn serialize(&self) -> String {
+ format!(r#"{{\n "id": "{}",\n "created_on": {}\n}}"#, self.id, self.created_on)
+ }
+
+ pub fn deserialize(input: &str) -> Option<Metadata> {
+ let clean_input = input
+ .chars()
+ .filter(|c| !c.is_whitespace())
+ .collect::<String>();
+
+ let id = Metadata::read_field(&clean_input, "id")?;
+ let created_on = Metadata::read_field(&clean_input, "createdOn")
+ .or_else(|| Metadata::read_field(&clean_input, "created_on"))?;
+
+ Some(Metadata {
+ id,
+ created_on: created_on.parse().ok()?
+ })
+ }
+
+ pub fn read_or_create(file_path: &PathBuf) -> Metadata {
+ match Metadata::read_metadata_file(file_path) {
+ Some(metadata) => metadata,
+ None => {
+ let timestamp = SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .map(|duration| duration.as_millis() as u128)
+ .unwrap_or_else(|_| 0);
+ return Metadata {
+ id: timestamp.to_string(),
+ created_on: timestamp
+ }
+ }
+ }
+ }
+
+ fn read_metadata_file(file_path: &PathBuf) -> Option<Metadata> {
+ let mut file = File::open(file_path).ok()?;
+ let mut contents = String::new();
+ file.read_to_string(&mut contents).ok()?;
+ Metadata::deserialize(&contents)
+ }
+
+
+ fn read_field(input: &str, field_name: &str) -> Option<String> {
+ let key_pattern = format!(r#""{}":""#, field_name);
+ input.find(&key_pattern)
+ .and_then(|start| {
+ let value_start = start + key_pattern.len();
+ let value_end = input[value_start..]
+ .find(|c: char| c == ',' || c == '}' || c == '\n')
+ .unwrap_or_else(|| input[value_start..].len()) + value_start;
+
+ let raw_value = &input[value_start..value_end];
+ let value = raw_value.trim_matches('"').to_string();
+ Some(value)
+ })
+ }
+}