aeruginous/
lib.rs

1/*********************** GNU General Public License 3.0 ***********************\
2|                                                                              |
3|  Copyright (C) 2023 Kevin Matthes                                            |
4|                                                                              |
5|  This program is free software: you can redistribute it and/or modify        |
6|  it under the terms of the GNU General Public License as published by        |
7|  the Free Software Foundation, either version 3 of the License, or           |
8|  (at your option) any later version.                                         |
9|                                                                              |
10|  This program is distributed in the hope that it will be useful,             |
11|  but WITHOUT ANY WARRANTY; without even the implied warranty of              |
12|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               |
13|  GNU General Public License for more details.                                |
14|                                                                              |
15|  You should have received a copy of the GNU General Public License           |
16|  along with this program.  If not, see <https://www.gnu.org/licenses/>.      |
17|                                                                              |
18\******************************************************************************/
19
20//! <!------------------- #[aeruginous::mercy::0003::start] ------------------->
21//!
22//! [ci]:  https://github.com/kevinmatthes/aeruginous-rs/workflows/ci/badge.svg
23//! [crate]:  https://crates.io/crates/aeruginous
24//! [crates-io]:  https://img.shields.io/crates/v/aeruginous
25//! [deps]:  https://deps.rs/repo/github/kevinmatthes/aeruginous-rs/status.svg
26//! [deps-rs]:  https://deps.rs/repo/github/kevinmatthes/aeruginous-rs
27//! [docs]:  https://docs.rs/aeruginous/badge.svg
28//! [docs-rs]:  https://docs.rs/aeruginous
29//! [downloads]:  https://img.shields.io/crates/d/aeruginous
30//! [gpl3]:  https://github.com/kevinmatthes/aeruginous-rs/blob/main/LICENSE
31//! [lcns]:  https://img.shields.io/github/license/kevinmatthes/aeruginous-rs
32//! [lst]:  https://img.shields.io/github/last-commit/kevinmatthes/aeruginous-rs
33//! [msrv]:  https://img.shields.io/badge/MSRV-1.80.0-brightgreen
34//! [release]:  https://github.com/kevinmatthes/aeruginous-rs/releases/latest
35//! [renovate]:  https://img.shields.io/badge/renovate-enabled-brightgreen.svg
36//! [repository]:  https://github.com/kevinmatthes/aeruginous-rs
37//! [tag]:  https://img.shields.io/github/v/tag/kevinmatthes/aeruginous-rs
38//!
39//! <!-------------------- #[aeruginous::mercy::0003::end] -------------------->
40//!
41//! <p align = 'center'>
42//! <a href = 'https://github.com/kevinmatthes/aeruginous-rs'>
43//! <img
44//!   height = '200'
45//!   src =
46//!     'https://github.com/kevinmatthes/aeruginous-rs/raw/main/aeruginous.svg'
47//! />
48//! </a>
49//! <br/>
50//! The Aeruginous Open Source Development Toolbox
51//! </p>
52//!
53//! ## Summary
54//!
55//! [![][ci]][repository]
56//! [![][lst]][repository]
57//! [![][lcns]][repository]
58//! [![][renovate]][repository]
59//! [![][tag]][release]
60//! <br>
61//! [![][crates-io]][crate]
62//! [![][deps]][deps-rs]
63//! [![][docs]][docs-rs]
64//! [![][downloads]][crate]
65//! [![][msrv]][repository]
66//!
67//! 1. [License](#license)
68//! 1. [Dependencies](#dependencies)
69//! 1. [Introduction](#introduction)
70//! 1. [Installation](#installation)
71//! 1. [Supported Subcommands](#supported-subcommands)
72//!    1. [`cff-create`](#cff-create)
73//!    1. [`cffreference`](#cffreference)
74//!    1. ⚠️  [`cff-release-today`](#cff-release-today) (deprecated)
75//!    1. [`comment-changes`](#comment-changes)
76//!    1. [`complain`](#complain)
77//!    1. [`increment-version`](#increment-version)
78//!    1. [`mkcws`](#mkcws)
79//!    1. [`ronlog`](#ronlog)
80//!    1. [`rs2md`](#rs2md)
81//!    1. [`uncrlf`](#uncrlf)
82//! <!--
83//!    1. [`cff-create`](#cff-create)
84//!    1. [`cffreference`](#cffreference)
85//!    1. ⚠️  [`cff-release-today`](#cff-release-today) (deprecated)
86//!    1. [`comment-changes`](#comment-changes)
87//!    1. [`complain`](#complain)
88//!    1. [`graph-description`](#graph-description)
89//!    1. [`increment-version`](#increment-version)
90//!    1. [`mkcws`](#mkcws)
91//!    1. [`ronlog`](#ronlog)
92//!    1. [`rs2md`](#rs2md)
93//!    1. [`uncrlf`](#uncrlf)
94//! -->
95//!
96//! The current code coverage is **<!-- cov -->74.05%<!-- cov -->**.
97//!
98//! ## License
99//!
100//! This project's license is **GPL-3.0**.  The whole license text can be found
101//! in [`LICENSE`][gpl3] in the repository root.  The brief version is as
102//! follows:
103//!
104//! > Copyright (C) 2023 Kevin Matthes
105//! >
106//! > This program is free software: you can redistribute it and/or modify
107//! > it under the terms of the GNU General Public License as published by
108//! > the Free Software Foundation, either version 3 of the License, or
109//! > (at your option) any later version.
110//! >
111//! > This program is distributed in the hope that it will be useful,
112//! > but WITHOUT ANY WARRANTY; without even the implied warranty of
113//! > MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
114//! > GNU General Public License for more details.
115//! >
116//! > You should have received a copy of the GNU General Public License
117//! > along with this program.  If not, see <https://www.gnu.org/licenses/>.
118//!
119//! ## Dependencies
120//!
121//! ### GitHub Actions
122//!
123//! - baptiste0928/cargo-install
124//!   [![](https://img.shields.io/github/license/baptiste0928/cargo-install)
125//!   ](https://github.com/baptiste0928/cargo-install)
126//!
127//! - fregante/setup-git-user
128//!   [![](https://img.shields.io/github/license/fregante/setup-git-user)
129//!   ](https://github.com/fregante/setup-git-user)
130//!
131//! ### Rust
132//!
133//! - [`aeruginous_io`]
134//!   [![](https://img.shields.io/crates/l/aeruginous-io)
135//!   ](https://github.com/kevinmatthes/aeruginous-io)
136//!
137//! - [`anstyle`]
138//!   [![](https://img.shields.io/crates/l/anstyle)
139//!   ](https://github.com/rust-cli/anstyle)
140//!
141//! - [`cargo_lock`]
142//!   [![](https://img.shields.io/crates/l/cargo-lock)
143//!   ](https://github.com/rustsec/rustsec)
144//!
145//! - [`chrono`]
146//!   [![](https://img.shields.io/crates/l/chrono)
147//!   ](https://github.com/chronotope/chrono)
148//!
149//! - [`clap`]
150//!   [![](https://img.shields.io/crates/l/clap)
151//!   ](https://github.com/clap-rs/clap)
152//!
153//! - [`git2`]
154//!   [![](https://img.shields.io/crates/l/git2)
155//!   ](https://github.com/rust-lang/git2-rs)
156//!
157//! - [`indexmap`]
158//!   [![](https://img.shields.io/crates/l/indexmap)
159//!   ](https://github.com/bluss/indexmap)
160//!
161//! - [`quick_xml`]
162//!   [![](https://img.shields.io/crates/l/quick-xml)
163//!   ](https://github.com/tafia/quick-xml)
164//!
165//! - [`ron`]
166//!   [![](https://img.shields.io/crates/l/ron)
167//!   ](https://github.com/ron-rs/ron)
168//!
169//! - [`serde`]
170//!   [![](https://img.shields.io/crates/l/serde)
171//!   ](https://github.com/serde-rs/serde)
172//!
173//! - [`sysexits`]
174//!   [![](https://img.shields.io/crates/l/sysexits)
175//!   ](https://github.com/sorairolake/sysexits-rs)
176//!
177//! - [`toml`]
178//!   [![](https://img.shields.io/crates/l/toml)
179//!   ](https://github.com/toml-rs/toml)
180//!
181//! ## Introduction
182//!
183//! `aeruginous` is a Rust application providing several development utilities.
184//!
185//! When searching a name for this project, one main requirement was to reflect
186//! both the originally intended main purpose of tracking time as well as the
187//! coding language this CLI is written in, Rust.  The adjective *aeruginous*
188//! fulfills both criteria as it means that the described noun has patina, a
189//! special form of rust which appears after a certain period of time has
190//! passed.
191//!
192//! Originally, it was planned to be a time tracking CLI but during the
193//! development of the first stable version, certain common tasks needed to be
194//! fulfilled repeatedly.  Since the application already had a somehow stable
195//! calling interface, the solutions to these tasks were added as subcommands
196//! to `aeruginous` in order to provide a convenient and time efficient
197//! automation.  One major advantage of doing so is the reduced maintenance
198//! effort and overall setup overhead because there is only one project to
199//! maintain instead multiple ones.
200//!
201//! This is how the idea arose to design `aeruginous` to be a toolbox instead
202//! of only a time tracker.
203//!
204//! ## Installation
205//!
206//! To download the latest stable version from [`crates.io`][crate], run the
207//! following command.
208//!
209//! ```bash
210//! cargo install aeruginous
211//! ```
212//!
213//! To install the latest nightly version from sources, Cargo also supports the
214//! installation from the current repository state.
215//!
216//! ```bash
217//! cargo install --git https://github.com/kevinmatthes/aeruginous-rs
218//! ```
219//!
220//! ## Supported Subcommands
221//!
222//! ### `cff-create`
223//!
224//! > To be called with:
225//! >
226//! > - `cffcreate`
227//! > - `cff-create`
228//! > - `mkcff`
229//!
230//! > To be installed with:
231//! >
232//! > - `-F cff-create`
233//!
234//! This mode will analyse a given project manifest and create an initial
235//! CITATION.cff from it.  Please note that the result does not necessarily
236//! validate such that further adjustments are recommended.
237//!
238//! Supported manifest formats are:
239//!
240//! - Cargo.toml (`rs`)
241//!
242//! ### `cffreference`
243//!
244//! > To be called with:
245//! >
246//! > - `cffref`
247//! > - `cff-ref`
248//! > - `cffreference`
249//! > - `cff-reference`
250//!
251//! CFF makes software citable.  Projects exposing a `CITATION.cff` can be cited
252//! with APA plain text citations, BibTeX database entries, and also in another
253//! `CITATION.cff`'s list of references.
254//!
255//! This subcommand grabs the citation information of the named source CFF file
256//! and pastes it at the end of the given output file.
257//!
258//! If the input file is omitted, the input information are attemted to be read
259//! from [`std::io::Stdin`].  Likewise, omitting the output file will cause
260//! `cffreference` to write to [`std::io::Stdout`].
261//!
262//! ### `cff-release-today`
263//!
264//! ⚠️  This mode is deprecated.  Please use
265//! [`increment-version`](#increment-version) instead.  ⚠️
266//!
267//! > To be called with:
268//! >
269//! > - `cffrel`
270//! > - `cff-rel`
271//! > - `cffreleasetoday`
272//! > - `cff-release-today`
273//!
274//! This subcommand will set the release date in the given `CITATION.cff` to the
275//! present day.
276//!
277//! ### `comment-changes`
278//!
279//! > To be called with:
280//! >
281//! > - `changelog`
282//! > - `comment-changes`
283//!
284//! It is a good practice to document changes to the code base in a CHANGELOG.
285//! This mode will read the recent commit messages and try to create a fragment
286//! for the CHANGELOG.
287//!
288//! This mode requires the specification of a delimiter separating the CHANGELOG
289//! category from an entry for that category.  The application will browse the
290//! Git history for commits which contain that delimiter in their messages and
291//! split those messages at the first occurence of that delimiter; users are
292//! free to choose whether to prefer the commits' summaries or their bodies,
293//! defaulting to the former.  The count of commits to harvest can be controlled
294//! by either an exact number, a commit SHA to stop at, or by omitting any stop
295//! condition to consider all commits in the entire history.  Each commit which
296//! does not contain the given delimiter in its message will be skipped.  The
297//! resulting CHANGELOG fragment will be stored either in the current working
298//! directory or in the given alternative directory.  The file name will consist
299//! of a time stamp, the configured Git username, and some information on the
300//! current branch.  The file format can be either reStructured Text (RST),
301//! Markdown (MD), or the Rusty Object Notation (RON).  At option, hyperlinks
302//! can be specified.
303//!
304//! As an example, a repository might contain these four commits:
305//!
306//! 1. ```Added ::= source file `a.rs`_```
307//! 2. ```Added ::= source file `b.rs`_```
308//! 3. `Update c.rs`
309//! 4. ```Fixed ::= known bug in `d.rs`_```
310//!
311//! To extract the changes from only these four commits, the application would
312//! need to be called with the following command.
313//!
314//! ```bash
315//! aeruginous comment-changes \
316//!   -d ::= \
317//!   -n 4 \
318//!   -o directory/ \
319//!   -l a.rs -t src/a.rs \
320//!   -l b.rs -t src/b.rs \
321//!   -l d.rs -t src/d.rs
322//! ```
323//!
324//! If this command is invoked by a user named Emma Xample on 1st January 1970
325//! at 01.23 am with the branch `example/test` being checked out, the resulting
326//! fragment will be stored as `directory/19700101_012345_Emma_Xample_test.rst`.
327//! The file contents will be the following:
328//!
329//! ```rst
330//! .. _a.rs:  src/a.rs
331//! .. _b.rs:  src/b.rs
332//! .. _d.rs:  src/d.rs
333//!
334//! Added
335//! .....
336//!
337//! - source file `a.rs`_
338//!
339//! - source file `b.rs`_
340//!
341//! Fixed
342//! .....
343//!
344//! - known bug in `d.rs`_
345//!
346//! ```
347//!
348//! ### `complain`
349//!
350//! > To be called with:
351//! >
352//! > - `complain`
353//!
354//! This application mode is a little linter to check whether the following
355//! requirements are met:
356//!
357//! 1. Every file needs to be terminated by a line feed.
358//! 1. Files must not contain CRLFs.
359//! 1. Lines shall have a width of at most n characters.
360//! 1. Trailing white space characters must be removed.
361//! 1. Lines have to be indented by spaces / tabs.
362//! 1. Spaces and tabs must not be mixed for indentation.
363//! 1. Within any line, there shall not be any tab character.
364//!
365//! All rules can be ignored, the line width as well as the indentation unit can
366//! be configured.  Every violation is reported to [`std::io::Stderr`] with the
367//! number of the rule being highlighted using the following colours.
368//!
369//! | Colour | Meaning                       |
370//! |:------:|:------------------------------|
371//! | green  | easy to fix                   |
372//! | yellow | moderate difficulty of fixing |
373//! | red    | major changes required to fix |
374//!
375//! After all rules have been checked for one file, a summary will be written to
376//! [`std::io::Stderr`] consisting of an ASCII art crab as this application is
377//! written in Rust, the number of violations, as well as the file name.
378//!
379//! <!--
380//! ### `graph-description`
381//!
382//! > To be called with:
383//! >
384//! > - `agd`
385//! > - `graph-description`
386//!
387//! The Aeruginous Graph Description is a very easy to learn coding language to
388//! describe the structure of graphs.  The language itself is based on plain
389//! English to ensure that learning does not require any programming skills at
390//! all.
391//!
392//! This mode is not finished, yet, but it can already detect some issues
393//! regarding given input files.
394//! -->
395//!
396//! ### `increment-version`
397//!
398//! > To be called with:
399//! >
400//! > - incver
401//! > - inc-ver
402//! > - incrementversion
403//! > - increment-version
404//!
405//! This subcommand will increment the hard-coded version strings in the given
406//! files by the specified version range.
407//!
408//! ### `mkcws`
409//!
410//! > To be called with:
411//! >
412//! > - `mkcws`
413//!
414//! > To be installed with:
415//! >
416//! > - `-F mkcws`
417//!
418//! IDEs based on the source code of Visual Studio Code have the interesting
419//! feature of keeping the current editor view across subsequent sessions.  When
420//! starting the IDE, it will restore the latest state in order to enable a
421//! seamless continuation of work.  Users are allowed to export the current view
422//! as a Code Workspace to save their access to multiple editor states.  These
423//! Code Workspaces are configuration files using a JSON-based notation in order
424//! to store information on the Workspace's root directory as well as some
425//! optional settings unique to that particular Workspace.
426//!
427//! Usually, operating systems can be configured regarding the default
428//! application for handling a certain file type.  This also holds for Code
429//! Workspaces.  If the operating system is set to open Code Workspaces with a
430//! Visual Studio Code-like IDE, the Code Workspaces can be used as project
431//! launching shortcuts for a convenient user expericence with the IDE.
432//!
433//! This application mode aims to simplify the creation of new Code Workspace
434//! files by the provision of a rather simple and intuitive command line
435//! interface to define a minimal and valid Code Workspace from scratch.
436//!
437//! ### `ronlog`
438//!
439//! > To be called with:
440//! >
441//! > - `ronlog`
442//!
443//! This mode will collect the RON fragments created by `comment-changes` and
444//! assemble them to a RON CHANGELOG.
445//!
446//! A RONLOG consists of multiple sections, sorted descendingly by the
447//! respective versions they are documenting.  New sections are inserted into
448//! that sorted list without breaking the sorting.  For example, if a particular
449//! RONLOG should contain sections for some versions v1.0.0, v0.2.0, and v0.1.0,
450//! a new section on v0.3.0 would be inserted between v1.0.0 and v0.2.0.
451//!
452//! ### `rs2md`
453//!
454//! > To be called with:
455//! >
456//! > - `rs2md`
457//!
458//! Source code should always be documented.  Rust's documentation system
459//! supports Markdown syntax in documentation comments.  Thus, it is a
460//! convenient decision to create a Rust project's README file from the crate
461//! root's documentation.  This command is also helpful to check the
462//! documentation comments for typos.
463//!
464//! When called, the subcommand accepts a list of input files to read from.  If
465//! no input file is given, `rs2md` will read from [`std::io::Stdin`].  At
466//! option, an output file can be specified where the results will be written
467//! to.  If omitted, the results will be written to [`std::io::Stdout`].
468//!
469//! Users are free to choose whether they would like to extract Rust comments
470//! starting with `//!` (outer comments) or comments starting with `///` (inner
471//! comments).  If neither option is given, nothing will be extracted.
472//!
473//! ### `uncrlf`
474//!
475//! > To be called with:
476//! >
477//! > - `uncrlf`
478//!
479//! Source code should have a uniform appearance.  Some text editors terminate
480//! lines by Carriage Return Line Feeds (CRLFs, `\r\n`).  This subcommand will
481//! remove those from the given file.
482//!
483//! <!------------------------------------------------------------------------->
484
485#![doc(
486    html_logo_url = "https://github.com/kevinmatthes/aeruginous-rs/raw/main/aeruginous.svg" // #[aeruginous::mercy::0003]
487)]
488#![deny(
489    clippy::all,
490    clippy::cargo,
491    clippy::complexity,
492    clippy::correctness,
493    clippy::nursery,
494    clippy::pedantic,
495    clippy::perf,
496    clippy::suspicious,
497    clippy::style,
498    dead_code,
499    deprecated,
500    missing_docs,
501    rustdoc::broken_intra_doc_links,
502    unreachable_code,
503    unused_assignments,
504    unused_imports,
505    unused_macros,
506    unused_must_use,
507    unused_mut,
508    unused_parens,
509    unused_variables
510)]
511#![allow(clippy::multiple_crate_versions)]
512
513mod application;
514mod cff;
515mod changelog;
516mod complain;
517mod graphing;
518mod increment_version;
519mod macros;
520mod pattern;
521mod running;
522mod traits;
523mod utilities;
524mod version;
525
526pub use crate::{
527    application::{Action, Clap as Application},
528    cff::Cffreference,
529    changelog::{
530        CommentChanges, Fragment, FragmentExportFormat, Ronlog, RonlogAction,
531        RonlogReferences, RonlogSection,
532    },
533    complain::{Complain, IndentationUnit},
534    graphing::{
535        AeruginousGraphDescription, AgdTokens, EdgeType, Edges, Graph,
536        VertexData, Vertices,
537    },
538    increment_version::IncrementVersion,
539    pattern::{
540        Buffer as PatternBuffer, IOProcessor as PatternIOProcessor,
541        Writer as PatternWriter,
542    },
543    running::Running,
544    traits::{
545        AppendAsLine, ColourMessage, ConvertBuffer, FromMd, FromRon, FromRst,
546        FromXml, Prefer, ToMd, ToRon, ToRst, ToStderr, ToXml,
547    },
548    version::{Range as VersionRange, Version},
549};
550
551#[cfg(feature = "cff-create")]
552pub use crate::cff::{
553    Create as CffCreate, ManifestType as CffCreateManifestType,
554};
555
556#[cfg(feature = "mkcws")]
557pub use crate::utilities::Mkcws;
558
559#[cfg(feature = "rs2md")]
560pub use crate::utilities::Rs2md;
561
562#[cfg(feature = "uncrlf")]
563pub use crate::utilities::Uncrlf;
564
565#[allow(deprecated)]
566pub use crate::traits::ReadFile;
567
568/// This crate's name.
569pub const NAME: &str = "aeruginous";
570
571/// This crate's self-description.
572pub const SELF_DESCRIPTION: &str =
573    "The Aeruginous Open Source Development Toolbox";
574
575/// This crate's version.
576pub const VERSION: &str = "v3.7.17";
577
578/******************************************************************************/