Skip to content

Commit

Permalink
Clean up (#1)
Browse files Browse the repository at this point in the history
* Add CI + code formatting

* Add documentation

* Fix actions not triggering

* Fix doc-test

* Ignore errors when removing the files

* Add changelog
  • Loading branch information
jonhkr authored Sep 7, 2020
1 parent a3c350a commit 7cdc858
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 36 deletions.
19 changes: 19 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
max_line_length = 120
tab_width = 4

[*.rs]
max_line_length = 100

[{*.har,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,jest.config}]
indent_size = 2

[{*.yaml,*.yml, *.toml}]
indent_size = 2
20 changes: 20 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Rust

on: [push, pull_request]

env:
CARGO_TERM_COLOR: always

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
- name: Run rustfmt
run: cargo fmt -- --check
12 changes: 7 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
[package]
name = "file-seq"
version = "0.1.3"
version = "0.2.0"
authors = ["Jonas Trevisan <[email protected]>"]
edition = "2018"
license = "MIT"
keywords = ["sequence", "file-sequence"]
categories = ["filesystem"]
repository = "https://github.com/jonhkr/rust-file-seq"
description = "Simple sequence that uses the file system as store"
description = "Fail-safe file sequence that uses the file system as store"
readme = "README.md"
exclude = [
"file-seq.iml"
"file-seq.iml",
".github"
]

[dependencies]
log = "0.4.8"
log = "0.4.11"

[dev-dependencies]
rand = "0.7.3"
rand = "0.7.3"
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ seq.increment_and_get(1).unwrap();
// Get, then increment by 1
seq.get_and_increment(1).unwrap();
```

## Changelog

### 0.2.0 (2020-09-07)
- Ignore errors on `FileSeq::delete` function (https://github.com/jonhkr/rust-file-seq/pull/1)
155 changes: 124 additions & 31 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
//! Fail-safe file sequence
//!
//! Works by versioning values of sequences and throwing away all versions,
//! but the current and the previous one.
//!
//! Inspired by [this Java implementation](https://commons.apache.org/proper/commons-transaction/apidocs/org/apache/commons/transaction/file/FileSequence.html)
//!
//! # Usage
//!
//! ```
//! use file_seq::FileSeq;
//! use std::path::Path;
//!
//! let dir = Path::new("/tmp/example");
//! let initial_value = 1;
//!
//! let seq = FileSeq::new(&dir, initial_value).unwrap();
//!
//! // Get current value
//! assert_eq!(initial_value, seq.value().unwrap());
//!
//! // Increment and get
//! assert_eq!(initial_value + 1, seq.increment_and_get(1).unwrap());
//!
//! // Get and then increment
//! assert_eq!(initial_value + 1, seq.get_and_increment(1).unwrap());
//! assert_eq!(initial_value + 2, seq.value().unwrap());
//! ```
use std::fs;
use std::io::{Error, ErrorKind, Read};
use std::path::{Path, PathBuf};
Expand All @@ -19,10 +48,7 @@ impl FileSeq {
let path_1 = store_path_buf.join("_1.seq");
let path_2 = store_path_buf.join("_2.seq");

let seq = Self {
path_1,
path_2,
};
let seq = Self { path_1, path_2 };

seq.initialize_if_necessary(initial_value)?;

Expand All @@ -37,22 +63,96 @@ impl FileSeq {
}
}

pub fn delete(&self) -> std::io::Result<()> {
fs::remove_file(&self.path_1)?;
fs::remove_file(&self.path_2)
/// Deletes this sequence
///
/// Once deleted, the sequence must be recreated
///
/// # Example
///
/// ```
/// use file_seq::FileSeq;
/// use std::path::Path;
///
/// let dir = Path::new("/tmp/example_delete");
/// let initial_value = 1;
///
/// let seq = FileSeq::new(&dir, initial_value).unwrap();
///
/// // Get current value
/// assert_eq!(initial_value, seq.value().unwrap());
///
/// seq.delete();
///
/// // Attempts to read the sequence after it's deleted returns an error
/// assert_eq!(seq.value().is_err(), true)
/// ```
pub fn delete(&self) -> () {
// The files might not exist already
let _ = fs::remove_file(&self.path_1);
let _ = fs::remove_file(&self.path_2);
}

/// Returns the current value of the sequence and then increments it.
///
/// # Example
///
/// ```
/// use file_seq::FileSeq;
/// use std::path::Path;
///
/// let dir = Path::new("/tmp/example_get_and_increment");
/// let initial_value = 1;
///
/// let seq = FileSeq::new(&dir, initial_value).unwrap();
///
/// assert_eq!(initial_value, seq.get_and_increment(1).unwrap());
/// assert_eq!(initial_value + 1, seq.value().unwrap());
///
/// ```
pub fn get_and_increment(&self, increment: u64) -> std::io::Result<u64> {
let value = self.read()?;
self.write(value + increment)?;
Ok(value)
}

/// Increments the sequence and return the value.
///
/// # Example
///
/// ```
/// use file_seq::FileSeq;
/// use std::path::Path;
///
/// let dir = Path::new("/tmp/example_increment_and_get");
/// let initial_value = 1;
///
/// let seq = FileSeq::new(&dir, initial_value).unwrap();
///
/// assert_eq!(initial_value + 1, seq.increment_and_get(1).unwrap());
/// assert_eq!(initial_value + 1, seq.value().unwrap());
///
/// ```
pub fn increment_and_get(&self, increment: u64) -> std::io::Result<u64> {
let value = self.get_and_increment(increment)?;
Ok(value + increment)
}

/// Returns the current value of the sequence.
///
/// # Example
///
/// ```
/// use file_seq::FileSeq;
/// use std::path::Path;
///
/// let dir = Path::new("/tmp/example_value");
/// let initial_value = 1;
///
/// let seq = FileSeq::new(&dir, initial_value).unwrap();
///
/// assert_eq!(initial_value, seq.value().unwrap());
///
/// ```
pub fn value(&self) -> std::io::Result<u64> {
self.read()
}
Expand All @@ -70,34 +170,27 @@ impl FileSeq {
}

match value2 {
Some(v2) => {
match value1 {
Some(v1) => {
if v2 > v1 {
Ok(v2)
} else {
warn!("Latest sequence value is smaller than backup, using backup.");
fs::remove_file(&self.path_2).ok();
Ok(v1)
}
}
None => {
Some(v2) => match value1 {
Some(v1) => {
if v2 > v1 {
Ok(v2)
} else {
warn!("Latest sequence value is smaller than backup, using backup.");
fs::remove_file(&self.path_2).ok();
Ok(v1)
}
}
}
None => Ok(v2),
},
None => {
fs::remove_file(&self.path_2).ok();

match value1 {
Some(v1) => {
Ok(v1)
}
None => {
Err(Error::new(
ErrorKind::InvalidData,
"Looks like both backup and latest sequence files are corrupted."))
}
Some(v1) => Ok(v1),
None => Err(Error::new(
ErrorKind::InvalidData,
"Looks like both backup and latest sequence files are corrupted.",
)),
}
}
}
Expand Down Expand Up @@ -127,7 +220,7 @@ impl FileSeq {
mod tests {
use std::env;
use std::fs;
use std::path::{PathBuf};
use std::path::PathBuf;

use rand::RngCore;

Expand Down Expand Up @@ -168,7 +261,7 @@ mod tests {
assert!(std::fs::metadata(dir).is_ok());
assert!(std::fs::metadata(&seq.path_2).is_ok());
seq.increment_and_get(1).unwrap();
seq.delete().unwrap();
seq.delete();
assert!(!std::fs::metadata(&seq.path_1).is_ok());
assert!(!std::fs::metadata(&seq.path_2).is_ok());
}
Expand All @@ -192,4 +285,4 @@ mod tests {
assert_eq!(prev_value, curr_value);
assert_eq!(curr_value + 1, seq.value().unwrap())
}
}
}

0 comments on commit 7cdc858

Please sign in to comment.