Skip to content

Commit

Permalink
Add support for multiple DOIs (#94)
Browse files Browse the repository at this point in the history
* Add support for multiple DOIs

* Update Readme

Closes #93
  • Loading branch information
nathansam authored Aug 24, 2024
1 parent c5c1789 commit 048c0da
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 55 deletions.
18 changes: 16 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
# Changelog

## bibget 1.1.0

### Features

Multiple DOIs can now be provided by separating them with a space.

### Bug fixes

-h (--help) and -V (--version) flags should now work again.

### Documentation

Readme updated to describe the new multiple DOI feature.

## bibget 1.0.5

### Changed

The authors key is now parsed correctly (commas in a bibtex key shouldn't start
a new line)
The authors key is now formmated correctly (commas in a bibtex key shouldn't
start a new line now)

### Dependencies removed

Expand Down
71 changes: 70 additions & 1 deletion Cargo.lock

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

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bibget"
version = "1.0.5"
version = "1.1.0"
edition = "2021"
authors = ["Nathan Constantine-Cooke <nathan.constantine-cooke@ed.ac.uk>"]
license = "MIT OR Apache-2.0"
Expand All @@ -15,7 +15,8 @@ repository = "https://github.com/nathansam/bibget"
tokio = { version = "1.39.3", features = ["full"], default-features = false }
futures = { default-features = false, version = "0.3.30" }
doi2bib = "0.2.0"
clap = {version = "4.5.13", features = ["derive", "std"], default-features = false }
clap = { version = "4.5.16", features = ["derive"] }


[dev-dependencies]
assert_cmd = "2.0.16"
Expand Down
51 changes: 42 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,44 @@
# bibget

[![CI](https://github.com/nathansam/bibget/actions/workflows/rust.yml/badge.svg)](https://github.com/nathansam/bibget/actions/workflows/rust.yml) [![crates.io](https://img.shields.io/crates/v/bibget.svg)](https://crates.io/crates/bibget) [![dependency status](https://deps.rs/repo/github/nathansam/bibget/status.svg)](https://deps.rs/repo/github/nathansam/bibget) [![MIT](https://img.shields.io/crates/l/bibget.svg)](https://github.com/nathansam/bibget/blob/master/LICENSE)
[![CI](https://github.com/nathansam/bibget/actions/workflows/rust.yml/badge.svg)](https://github.com/nathansam/bibget/actions/workflows/rust.yml) [![crates.io](https://img.shields.io/crates/v/bibget.svg)](https://crates.io/crates/bibget) [![dependency status](https://deps.rs/repo/github/nathansam/bibget/status.svg)](https://deps.rs/repo/github/nathansam/bibget) [![MIT](https://img.shields.io/crates/l/bibget.svg)](https://github.com/nathansam/bibget/blob/master/LICENSE)

CLI tool to generate a BibTex entry from a DOI. Written in Rust and based on the [`doi2bib` crate](https://crates.io/crates/doi2bib).
Command line interface tool for generating BibTex entries from DOIs. Written in
Rust and based on the [`doi2bib` crate](https://crates.io/crates/doi2bib).

## Installation

`bibget` can be installed from source using `cargo`


Pre-compiled binaries for MacOS and Linux are available from the
[releases page](https://github.com/nathansam/bibget/releases) and do not require
Rust to be installed.

`bibget` can be installed from source using `cargo`. The most stable version is
hosted on [crates.io](https://crates.io/crates/bibget).

``` bash
# release version from crates.io
cargo install bibget
```

You can also install from GitHub if you want access to the latest pre-release
(likely with newer dependencies) or development (more experimental) builds.

# development version from GitHub
``` bash
# pre-release version
cargo install --git https://github.com/nathansam/bibget.git bibget
# development version
cargo install --git https://github.com/nathansam/bibget.git --branch dev bibget
```

## Usage

`bibget` supports an optional `-f/--file` argument for writing the BibTex entry to a file. The file will automatically be created if it does not already exist. If the file exists then the entry will be appended to the file.
`bibget` is a command line tool that takes a DOI as an argument and returns
output in BibTex format. Multiple DOIs can be passed via whitespace separation.

``` bash
> bibget -f test.bib 10.1002/sim.1186
bibget 10.1002/sim.1186 10.1007/978-3-319-19425-7
```

```
``` bibtex
@article{Higgins_2002,
title = {Quantifying heterogeneity in a meta‐analysis},
volume = {21},
Expand All @@ -42,4 +53,26 @@ cargo install --git https://github.com/nathansam/bibget.git bibget
month = may,
pages = {1539–1558}
}
@book{Harrell__2015,
_2015,
title = {Regression Modeling Strategies: With Applications to Linear Models, Logistic and Ordinal Regression, and Survival Analysis},
ISBN = {9783319194257},
ISSN = {2197-568X},
url = {http://dx.doi.org/10.1007/978-3-319-19425-7},
DOI = {10.1007/978-3-319-19425-7},
journal = {Springer Series in Statistics},
publisher = {Springer International Publishing},
author = {Harrell , Frank E.},
year = {2015}
}
```

`bibget` supports an optional `-f/--file` flag for writing the BibTex to
file. If the specified file does not already exist, it will be created first.
Entries will be appended to the end of existing files instead.

``` bash
> bibget -f test.bib 10.1002/sim.1186
```
96 changes: 55 additions & 41 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,68 +6,82 @@ use std::io::Write;
#[clap(
author = "Nathan Constantine-Cooke",
version,
about = "Simple tool to convert a DOI to a BibTeX entry and (optionally) append it to a file."
about = "Simple tool to convert DOI(s) to BibTeX and (optionally) write to storage."
)]
struct Cli {
/// The path to the file to written to. If not specified, the BibTex entry will only be printed to stdout.
#[clap(short = 'f', long = "file", required = false, default_value = "none")]
file: String,
/// The DOI to look up
#[clap()]
doi: String,
/// A path for writing the BibTex to. The file will be created if it does not already exist or appended to if it already exists.
#[clap(short, long, required = false, default_value = None)]
file: Option<String>,

/// The DOI(s) to convert. Multiple DOIs should be separated by spaces.
#[clap(value_delimiter = ' ', num_args = 1..)]
doi: Vec<String>,
}

#[tokio::main]
async fn main() {
let args = Cli::parse();
let doi = args.doi;
let doi2bib = doi2bib::Doi2Bib::new().unwrap();
let bibtex_result = doi2bib.resolve_doi(&doi).await;
let doi_vec = args.doi;
let file = args.file;
let mut format_bibtex_combined = String::from("");

let mut it = doi_vec.iter().peekable();
while let Some(doi) = it.next() {
let doi2bib = doi2bib::Doi2Bib::new().unwrap();
let bibtex_result = doi2bib.resolve_doi(doi).await;

let bibtex = match bibtex_result {
Ok(file) => file,
Err(e) => {
if e.is_status() {
println!("❌ Getting the BibTex entry failed. Please check the DOI is valid and you have internet access.");
std::process::exit(1);
let bibtex = match bibtex_result {
Ok(file) => file,
Err(e) => {
if e.is_status() {
println!("❌ Getting the BibTex entry failed. Please check the DOI is valid and you have internet access.");
std::process::exit(1);
} else {
panic!("Error: {}", e)
}
}
};
// Count the number of layers curly braces to ensure we only add newlines
// after the first level of curly braces (i.e between new BibTex keys)
let mut curly_count = 0;
// Format BibTex output to be more readable (new lines and spaces)
let mut format_bibtex = String::from("");

for char in bibtex.chars() {
if char == '{' {
curly_count += 1;
} else if char == '}' {
curly_count -= 1;
}
if char == ',' && curly_count == 1 {
format_bibtex.push_str(",\n ");
} else {
panic!("Error: {}", e)
format_bibtex.push(char);
}
}
};
// Count the number of layers curly braces to ensure we only add newlines
// after the first level of curly braces (i.e between new BibTex keys)
let mut curly_count = 0;
// Format BibTex output to be more readable (new lines and spaces)
let mut format_bibtex = String::from("");

for char in bibtex.chars() {
if char == '{' {
curly_count += 1;
} else if char == '}' {
curly_count -= 1;
}
if char == ',' && curly_count == 1 {
format_bibtex.push_str(",\n ");
} else {
format_bibtex.push(char);
format_bibtex = format_bibtex.replace("} }", "}\n}"); // Format final line
format_bibtex = format_bibtex.replace(" }", "}");
format_bibtex = format_bibtex.replace("=", " = "); // Add spaces around equals sign
format_bibtex_combined.push_str(&format_bibtex);

if it.peek().is_some() {
format_bibtex_combined.push('\n');
}
}

format_bibtex = format_bibtex.replace("} }", "}\n}"); // Format final line
format_bibtex = format_bibtex.replace("=", " = "); // Add spaces around equals sign

println!("{format_bibtex}");
println!("{format_bibtex_combined}");

// Write to file (if specified)
let file = args.file;
if file != "none" {

if file.is_some() {
let mut f = OpenOptions::new()
.append(true)
.create(true) // Optionally create the file if it doesn't already exist
.open(file)
.open(file.unwrap())
.expect("Unable to open file");
f.write_all(format_bibtex.as_bytes())

f.write_all(format_bibtex_combined.as_bytes())
.expect("Unable to write data");
}
}

0 comments on commit 048c0da

Please sign in to comment.