···11# Safir
2233-Repo containing the source for `safir` and `safir-mem`.
33+Simple CLI key/value store.
44+55+Store key/value pairs in the terminal and retrieve them later for use like in different shell sessions.
66+77+## Install
88+99+To install `safir`, run `cargo install safir`.
1010+1111+To build from source, clone the repository and run:
1212+1313+```bash
1414+cargo build --release
1515+```
1616+1717+Then move the binary to somewhere in your `$PATH`
1818+1919+## Usage
2020+2121+When `safir` is run, it creates a store file in your `$HOME` directory (`$HOME/.safirstore/safirstore.json`).
2222+2323+Run `safir --help` for usage:
2424+2525+```bash
2626+Key/Value store to share information between shell sessions
2727+2828+Usage: safir <COMMAND>
2929+3030+Commands:
3131+ add Add a value to the store with the given key
3232+ get Get values from the store
3333+ rm Remove values from the store
3434+ alias Output the alias command for key / value pairs
3535+ export Output the export command for a key / value pairs
3636+ list List all values in the store
3737+ clear Clear all keys/values from the store
3838+ purge Purges the .safirstore directory, removing it and its contents
3939+ help Print this message or the help of the given subcommand(s)
4040+4141+Options:
4242+ -h, --help Print help
4343+ -V, --version Print version
4444+```
4545+4646+## Examples
4747+4848+Adding a key and value to the store:
4949+5050+```bash
5151+safir add api_key "api_key_value"
5252+```
5353+5454+Retrieving a value from the store:
5555+5656+```bash
5757+safir get api_key
5858+# api_key="api_key_value"
5959+```
6060+6161+Removing a value from the store:
46255-:warning: `safir-mem` and `safir-core` are NO LONGER MAINTAINED :warning:
6363+```bash
6464+safir rm api_key
6565+```
66677-They will stay part of the repo for backward usage but the `safir` project has been reworked and brought back to its roots.
88-Everything now lives in the `safir` project.
6767+List all values in the store:
6868+6969+```bash
7070+safir list
7171+7272+# api_key="api_key_value"
7373+# another_api_key="another_value"
7474+```
7575+7676+Exporting a value:
7777+7878+```bash
7979+safir export api_key
8080+# export api_key="api_key_value"
8181+8282+$(safir export api_key) # <-- Will export the value to the current shell
8383+```
8484+8585+Aliasing a value:
8686+8787+```bash
8888+safir alias long_command
8989+# alias long_command="cd build/ && make && sudo make install"
9090+9191+$(safir alias long_command) # <-- Will alias the command in the current shell
9292+```
9393+9494+Clear the store:
9595+9696+```bash
9797+safir clear
9898+# Will remove all contents in the store
9999+```
100100+101101+Purge the store (remove EVERYTHING `safir` related)
102102+103103+```bash
104104+safir purge # Will remove the .safirstore directory
105105+```
···11- Apache License
22- Version 2.0, January 2004
33- http://www.apache.org/licenses/
44-55- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
66-77- 1. Definitions.
88-99- "License" shall mean the terms and conditions for use, reproduction,
1010- and distribution as defined by Sections 1 through 9 of this document.
1111-1212- "Licensor" shall mean the copyright owner or entity authorized by
1313- the copyright owner that is granting the License.
1414-1515- "Legal Entity" shall mean the union of the acting entity and all
1616- other entities that control, are controlled by, or are under common
1717- control with that entity. For the purposes of this definition,
1818- "control" means (i) the power, direct or indirect, to cause the
1919- direction or management of such entity, whether by contract or
2020- otherwise, or (ii) ownership of fifty percent (50%) or more of the
2121- outstanding shares, or (iii) beneficial ownership of such entity.
2222-2323- "You" (or "Your") shall mean an individual or Legal Entity
2424- exercising permissions granted by this License.
2525-2626- "Source" form shall mean the preferred form for making modifications,
2727- including but not limited to software source code, documentation
2828- source, and configuration files.
2929-3030- "Object" form shall mean any form resulting from mechanical
3131- transformation or translation of a Source form, including but
3232- not limited to compiled object code, generated documentation,
3333- and conversions to other media types.
3434-3535- "Work" shall mean the work of authorship, whether in Source or
3636- Object form, made available under the License, as indicated by a
3737- copyright notice that is included in or attached to the work
3838- (an example is provided in the Appendix below).
3939-4040- "Derivative Works" shall mean any work, whether in Source or Object
4141- form, that is based on (or derived from) the Work and for which the
4242- editorial revisions, annotations, elaborations, or other modifications
4343- represent, as a whole, an original work of authorship. For the purposes
4444- of this License, Derivative Works shall not include works that remain
4545- separable from, or merely link (or bind by name) to the interfaces of,
4646- the Work and Derivative Works thereof.
4747-4848- "Contribution" shall mean any work of authorship, including
4949- the original version of the Work and any modifications or additions
5050- to that Work or Derivative Works thereof, that is intentionally
5151- submitted to Licensor for inclusion in the Work by the copyright owner
5252- or by an individual or Legal Entity authorized to submit on behalf of
5353- the copyright owner. For the purposes of this definition, "submitted"
5454- means any form of electronic, verbal, or written communication sent
5555- to the Licensor or its representatives, including but not limited to
5656- communication on electronic mailing lists, source code control systems,
5757- and issue tracking systems that are managed by, or on behalf of, the
5858- Licensor for the purpose of discussing and improving the Work, but
5959- excluding communication that is conspicuously marked or otherwise
6060- designated in writing by the copyright owner as "Not a Contribution."
6161-6262- "Contributor" shall mean Licensor and any individual or Legal Entity
6363- on behalf of whom a Contribution has been received by Licensor and
6464- subsequently incorporated within the Work.
6565-6666- 2. Grant of Copyright License. Subject to the terms and conditions of
6767- this License, each Contributor hereby grants to You a perpetual,
6868- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
6969- copyright license to reproduce, prepare Derivative Works of,
7070- publicly display, publicly perform, sublicense, and distribute the
7171- Work and such Derivative Works in Source or Object form.
7272-7373- 3. Grant of Patent License. Subject to the terms and conditions of
7474- this License, each Contributor hereby grants to You a perpetual,
7575- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
7676- (except as stated in this section) patent license to make, have made,
7777- use, offer to sell, sell, import, and otherwise transfer the Work,
7878- where such license applies only to those patent claims licensable
7979- by such Contributor that are necessarily infringed by their
8080- Contribution(s) alone or by combination of their Contribution(s)
8181- with the Work to which such Contribution(s) was submitted. If You
8282- institute patent litigation against any entity (including a
8383- cross-claim or counterclaim in a lawsuit) alleging that the Work
8484- or a Contribution incorporated within the Work constitutes direct
8585- or contributory patent infringement, then any patent licenses
8686- granted to You under this License for that Work shall terminate
8787- as of the date such litigation is filed.
8888-8989- 4. Redistribution. You may reproduce and distribute copies of the
9090- Work or Derivative Works thereof in any medium, with or without
9191- modifications, and in Source or Object form, provided that You
9292- meet the following conditions:
9393-9494- (a) You must give any other recipients of the Work or
9595- Derivative Works a copy of this License; and
9696-9797- (b) You must cause any modified files to carry prominent notices
9898- stating that You changed the files; and
9999-100100- (c) You must retain, in the Source form of any Derivative Works
101101- that You distribute, all copyright, patent, trademark, and
102102- attribution notices from the Source form of the Work,
103103- excluding those notices that do not pertain to any part of
104104- the Derivative Works; and
105105-106106- (d) If the Work includes a "NOTICE" text file as part of its
107107- distribution, then any Derivative Works that You distribute must
108108- include a readable copy of the attribution notices contained
109109- within such NOTICE file, excluding those notices that do not
110110- pertain to any part of the Derivative Works, in at least one
111111- of the following places: within a NOTICE text file distributed
112112- as part of the Derivative Works; within the Source form or
113113- documentation, if provided along with the Derivative Works; or,
114114- within a display generated by the Derivative Works, if and
115115- wherever such third-party notices normally appear. The contents
116116- of the NOTICE file are for informational purposes only and
117117- do not modify the License. You may add Your own attribution
118118- notices within Derivative Works that You distribute, alongside
119119- or as an addendum to the NOTICE text from the Work, provided
120120- that such additional attribution notices cannot be construed
121121- as modifying the License.
122122-123123- You may add Your own copyright statement to Your modifications and
124124- may provide additional or different license terms and conditions
125125- for use, reproduction, or distribution of Your modifications, or
126126- for any such Derivative Works as a whole, provided Your use,
127127- reproduction, and distribution of the Work otherwise complies with
128128- the conditions stated in this License.
129129-130130- 5. Submission of Contributions. Unless You explicitly state otherwise,
131131- any Contribution intentionally submitted for inclusion in the Work
132132- by You to the Licensor shall be under the terms and conditions of
133133- this License, without any additional terms or conditions.
134134- Notwithstanding the above, nothing herein shall supersede or modify
135135- the terms of any separate license agreement you may have executed
136136- with Licensor regarding such Contributions.
137137-138138- 6. Trademarks. This License does not grant permission to use the trade
139139- names, trademarks, service marks, or product names of the Licensor,
140140- except as required for reasonable and customary use in describing the
141141- origin of the Work and reproducing the content of the NOTICE file.
142142-143143- 7. Disclaimer of Warranty. Unless required by applicable law or
144144- agreed to in writing, Licensor provides the Work (and each
145145- Contributor provides its Contributions) on an "AS IS" BASIS,
146146- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147147- implied, including, without limitation, any warranties or conditions
148148- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149149- PARTICULAR PURPOSE. You are solely responsible for determining the
150150- appropriateness of using or redistributing the Work and assume any
151151- risks associated with Your exercise of permissions under this License.
152152-153153- 8. Limitation of Liability. In no event and under no legal theory,
154154- whether in tort (including negligence), contract, or otherwise,
155155- unless required by applicable law (such as deliberate and grossly
156156- negligent acts) or agreed to in writing, shall any Contributor be
157157- liable to You for damages, including any direct, indirect, special,
158158- incidental, or consequential damages of any character arising as a
159159- result of this License or out of the use or inability to use the
160160- Work (including but not limited to damages for loss of goodwill,
161161- work stoppage, computer failure or malfunction, or any and all
162162- other commercial damages or losses), even if such Contributor
163163- has been advised of the possibility of such damages.
164164-165165- 9. Accepting Warranty or Additional Liability. While redistributing
166166- the Work or Derivative Works thereof, You may choose to offer,
167167- and charge a fee for, acceptance of support, warranty, indemnity,
168168- or other liability obligations and/or rights consistent with this
169169- License. However, in accepting such obligations, You may act only
170170- on Your own behalf and on Your sole responsibility, not on behalf
171171- of any other Contributor, and only if You agree to indemnify,
172172- defend, and hold each Contributor harmless for any liability
173173- incurred by, or claims asserted against, such Contributor by reason
174174- of your accepting any such warranty or additional liability.
175175-176176- END OF TERMS AND CONDITIONS
177177-178178- APPENDIX: How to apply the Apache License to your work.
179179-180180- To apply the Apache License to your work, attach the following
181181- boilerplate notice, with the fields enclosed by brackets "[]"
182182- replaced with your own identifying information. (Don't include
183183- the brackets!) The text should be enclosed in the appropriate
184184- comment syntax for the file format. We also recommend that a
185185- file or class name and description of purpose be included on the
186186- same "printed page" as the copyright notice for easier
187187- identification within third-party archives.
188188-189189- Copyright [yyyy] [name of copyright owner]
190190-191191- Licensed under the Apache License, Version 2.0 (the "License");
192192- you may not use this file except in compliance with the License.
193193- You may obtain a copy of the License at
194194-195195- http://www.apache.org/licenses/LICENSE-2.0
196196-197197- Unless required by applicable law or agreed to in writing, software
198198- distributed under the License is distributed on an "AS IS" BASIS,
199199- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200200- See the License for the specific language governing permissions and
201201- limitations under the License.
-21
safir-core/LICENSE-MIT
···11-MIT License
22-33-Copyright (c) 2023 Graham Keenan
44-55-Permission is hereby granted, free of charge, to any person obtaining a copy
66-of this software and associated documentation files (the "Software"), to deal
77-in the Software without restriction, including without limitation the rights
88-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
99-copies of the Software, and to permit persons to whom the Software is
1010-furnished to do so, subject to the following conditions:
1111-1212-The above copyright notice and this permission notice shall be included in all
1313-copies or substantial portions of the Software.
1414-1515-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1616-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1717-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121-SOFTWARE.
-12
safir-core/README.md
···11-# Safir Core
22-33-## Notice
44-55-:warning: This is now archived and no longer updated :warning:
66-77-It was ambitious (and worked kinda) but became far too unweildy and complicated when it didn't have to.
88-Maybe a rewrite in the future but for now, it's now archived.
99-1010-Internal library used by `safir` and `safir-mem` found [here](https://github.com/Tyrannican/safir)
1111-1212-Not intended for public use unless you want to contribute!
···11-//! Safir handles the logic of writing key/value pairs to disk
22-//!
33-//! Provides a simple wrapper around a Hash Map which stores values with given keys
44-//! to a JSON file on disk so that you can load them up in other shell sessions.
55-//!
66-//! Prevents the faff around having to add rely on shell history or RC files for items
77-//! that you don't usually want to persist around.
88-//!
99-//! Safir gives you the option to add / get / remove items from the store
1010-//! and to clear / purge when you're finished with them.
1111-use anyhow::Result;
1212-1313-use async_trait::async_trait;
1414-use colored::*;
1515-1616-use crate::config::SafirConfig;
1717-use crate::utils::{confirm_entry, print_header, print_headless, print_output};
1818-use crate::SafirEngine;
1919-use rubin::store::persistence::PersistentStore;
2020-2121-/// Safir Store (fancy wrapper around reading and writing to a JSON file)
2222-pub struct SafirStore {
2323- pub store: PersistentStore,
2424- pub headless: bool,
2525-}
2626-2727-impl SafirStore {
2828- /// Initialises the Safirstore if not already initialised
2929- pub async fn new(config: &SafirConfig) -> Result<Self> {
3030- let store_path = config.root_path.join("safirstore.json");
3131- let mut ps = if store_path.exists() {
3232- PersistentStore::from_existing(store_path).await?
3333- } else {
3434- PersistentStore::new(store_path).await?
3535- };
3636-3737- ps.set_write_on_update(true);
3838- let headless = config.get_headless_mode();
3939-4040- Ok(Self {
4141- store: ps,
4242- headless,
4343- })
4444- }
4545-4646- /// Display all key/values in the store
4747- pub fn display_all(&self) {
4848- let strings = self.store.get_string_store_ref();
4949- if self.headless {
5050- for (key, value) in strings.iter() {
5151- print_headless("", key, value);
5252- }
5353-5454- return;
5555- }
5656-5757- print_header();
5858- let mut output: String;
5959- for (key, value) in strings.iter() {
6060- output = format!("{}: \"{}\"", key.bold().yellow(), value);
6161- print_output(&output);
6262- }
6363- }
6464-6565- /// Remove the store directory and all contents
6666- pub fn purge(&self) {
6767- if confirm_entry("Are you sure you want to purge Safirstore?") {
6868- std::fs::remove_dir_all(&self.store.path)
6969- .expect("unable to remove safirstore directory");
7070- }
7171- }
7272-}
7373-7474-#[async_trait]
7575-impl SafirEngine for SafirStore {
7676- /// Add an entry to the store and write it out to disk
7777- async fn add_entry(&mut self, key: String, value: String) -> Result<()> {
7878- self.store.insert_string(&key, &value).await?;
7979- Ok(())
8080- }
8181-8282- /// Get an entry form the store by loading it from disk and displaying it
8383- async fn get_entry(&self, key: String) -> Result<()> {
8484- let value = if let Ok(val) = self.store.get_string(&key) {
8585- val
8686- } else {
8787- String::from("")
8888- };
8989-9090- if self.headless {
9191- print_headless("", &key, &value);
9292- return Ok(());
9393- }
9494-9595- print_header();
9696- let output = if !value.is_empty() {
9797- format!("{}: \"{}\"", key.bold().yellow(), value)
9898- } else {
9999- format!("{}: ", key.bold().yellow())
100100- };
101101-102102- print_output(&output);
103103-104104- Ok(())
105105- }
106106-107107- /// Remove a key/value pair from the store and update onto disk
108108- async fn remove_entry(&mut self, keys: Vec<String>) -> Result<()> {
109109- for key in &keys {
110110- self.store.remove_string(key).await?;
111111- }
112112-113113- Ok(())
114114- }
115115-116116- /// Outputs the key/value pair as a command with the prefix
117117- ///
118118- /// E.g. With a prefix of `alias` this will display the command as
119119- /// `alias {key}="{value}"` with {key} / {value} replaced with their values from the store
120120- async fn set_commands(&mut self, prefix: &str, keys: &Vec<String>) {
121121- if self.headless {
122122- for key in keys {
123123- if let Ok(value) = self.store.get_string(key) {
124124- print_headless(prefix, key, &value);
125125- }
126126- }
127127-128128- return;
129129- }
130130-131131- print_header();
132132- let prefix = match prefix {
133133- "alias" => "alias".bold().green(),
134134- "export" => "export".bold().magenta(),
135135- _ => prefix.bold(),
136136- };
137137- for key in keys {
138138- if let Ok(value) = self.store.get_string(key) {
139139- println!("{} {}=\"{}\"\n", prefix, key.bold().yellow(), value);
140140- }
141141- }
142142- }
143143-144144- /// Clear the the contents of the store and update onto disk
145145- async fn clear_entries(&mut self) -> Result<()> {
146146- if confirm_entry("Are you sure you want to clear the store?") {
147147- self.store.clear_strings().await?;
148148- }
149149-150150- Ok(())
151151- }
152152-153153- fn to_type(&self) -> &dyn std::any::Any {
154154- self
155155- }
156156-}
···11-use anyhow::Result;
22-use std::io::Write;
33-use std::path::{Path, PathBuf};
44-55-use crate::config::SafirConfig;
66-77-use colored::*;
88-use sysinfo::{Pid, System, SystemExt};
99-use tokio::fs;
1010-1111-pub async fn init() -> Result<SafirConfig> {
1212- let store_dir = create_safir_directory().await?;
1313- let cfg = load_safir_config(&store_dir).await?;
1414- Ok(cfg)
1515-}
1616-1717-pub fn check_rubin_installed() -> bool {
1818- if which::which("rubin").is_ok() {
1919- return true;
2020- }
2121-2222- false
2323-}
2424-2525-pub fn check_process_running(pid: u32) -> bool {
2626- let mut system = System::new_all();
2727- system.refresh_all();
2828- if system.process(Pid::from(pid as usize)).is_some() {
2929- return true;
3030- }
3131-3232- false
3333-}
3434-3535-pub fn is_safir_running(pid: Option<u32>) -> bool {
3636- match pid {
3737- Some(pid) => check_process_running(pid),
3838- None => false,
3939- }
4040-}
4141-4242-pub async fn path_exists(path: impl AsRef<Path>) -> bool {
4343- path.as_ref().exists()
4444-}
4545-4646-pub async fn create_safir_directory() -> Result<PathBuf> {
4747- let home_dir = dirs::home_dir().unwrap();
4848- let store_path = home_dir.join(".safirstore");
4949- fs::create_dir_all(&store_path).await?;
5050-5151- Ok(store_path)
5252-}
5353-5454-#[cfg(target_family = "unix")]
5555-pub async fn kill_process(pid: u32) -> Result<()> {
5656- if let Ok(process) = psutil::process::Process::new(pid) {
5757- if let Err(err) = process.kill() {
5858- eprintln!("failed to kill process: {}", err);
5959- }
6060- } else {
6161- eprintln!("failed to get process information");
6262- }
6363-6464- Ok(())
6565-}
6666-6767-#[cfg(target_os = "windows")]
6868-pub async fn kill_process(pid: u32) {
6969- println!("*** Windows -- This is experimental and may not work as intended! ***");
7070- let output = Command::new("taskkill")
7171- .arg("/F")
7272- .arg("/PID")
7373- .arg(pid.to_string())
7474- .output()
7575- .expect("failed to call taskkill");
7676-7777- if !output.status.success() {
7878- eprintln!("failed to terminate process");
7979- }
8080-}
8181-8282-/// Formats and prints the message to stdout
8383-pub fn print_output(msg: &str) {
8484- println!("{}\n", msg);
8585-}
8686-8787-/// Prints the Safirstore header
8888-pub fn print_header() {
8989- println!("{}", "--=Safirstore=--\n".bold());
9090-}
9191-9292-pub fn print_headless(prefix: &str, key: &str, value: &str) {
9393- if value == "" {
9494- return;
9595- }
9696-9797- let has_whitespace = value.contains(char::is_whitespace);
9898-9999- let output = if has_whitespace {
100100- format!("{}=\"{}\"", key, value)
101101- } else {
102102- format!("{}={}", key, value)
103103- };
104104-105105- if !prefix.is_empty() {
106106- println!("{} {}", prefix, output);
107107- } else {
108108- println!("{}", output);
109109- }
110110-}
111111-112112-/// Confirmation dialog for important calls
113113-pub fn confirm_entry(msg: &str) -> bool {
114114- let mut answer = String::new();
115115- print!("{} (y/n) ", msg);
116116- std::io::stdout().flush().expect("failed to flush buffer");
117117-118118- let _ = std::io::stdin()
119119- .read_line(&mut answer)
120120- .expect("unable to get input from user");
121121-122122- let answer = answer.trim().to_lowercase();
123123- if answer == "y" || answer == "yes" {
124124- return true;
125125- }
126126-127127- false
128128-}
129129-130130-pub async fn load_safir_config(store_dir: impl AsRef<Path>) -> Result<SafirConfig> {
131131- let cfg_path = &store_dir.as_ref().join("safir.cfg");
132132- let mut cfg = if path_exists(&cfg_path).await {
133133- SafirConfig::load(&cfg_path).await?
134134- } else {
135135- SafirConfig::new()
136136- };
137137-138138- cfg.root_path = store_dir.as_ref().to_owned();
139139- cfg.config_path = cfg_path.to_owned();
140140-141141- // Used in cases where the process has ended ungracefully and the config hasnt been updated
142142- if let Some(pid) = cfg.memcache_pid {
143143- if !check_process_running(pid) {
144144- cfg = SafirConfig::new();
145145- cfg.write().await?;
146146- }
147147- }
148148-149149- Ok(cfg)
150150-}
-21
safir-mem/CHANGELOG.md
···11-# Change Log
22-33-Documenting changes between versions
44-55-## v0.3.0
66-77-Removed formatted output
88-99-This makes more sense in the for safir-mem as it means you can easily evaluate output in the terminal
1010-1111-Better suits the use case.
1212-1313-## v0.2.1
1414-1515-Changes to the internal code structure, no changes to operation
1616-1717-## v0.2.0
1818-1919-Moved the core of the control to a new internal library called `safir-core`
2020-2121-No changes to operation but merits a version bump
-20
safir-mem/Cargo.toml
···11-[package]
22-name = "safir-mem"
33-version = "0.3.1"
44-edition = "2021"
55-authors = ["Graham Keenan graham.keenan@outlook.com"]
66-license = "MIT OR Apache-2.0"
77-description = "In-memory key/value store to share values between different shell sessions"
88-readme = "README.md"
99-homepage = "https://github.com/Tyrannican/safir"
1010-repository = "https://github.com/Tyrannican/safir"
1111-keywords = ["cli", "terminal", "utility", "key-value", "store"]
1212-categories = ["command-line-utilities"]
1313-1414-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1515-1616-[dependencies]
1717-clap = { version = "4.2.5" , features = ["derive"] }
1818-tokio = { version = "1.28.2", features = ["full"] }
1919-safir-core = { version = "0.2.2", path = "../safir-core" }
2020-anyhow = "1.0.75"
-201
safir-mem/LICENSE-APACHE
···11- Apache License
22- Version 2.0, January 2004
33- http://www.apache.org/licenses/
44-55- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
66-77- 1. Definitions.
88-99- "License" shall mean the terms and conditions for use, reproduction,
1010- and distribution as defined by Sections 1 through 9 of this document.
1111-1212- "Licensor" shall mean the copyright owner or entity authorized by
1313- the copyright owner that is granting the License.
1414-1515- "Legal Entity" shall mean the union of the acting entity and all
1616- other entities that control, are controlled by, or are under common
1717- control with that entity. For the purposes of this definition,
1818- "control" means (i) the power, direct or indirect, to cause the
1919- direction or management of such entity, whether by contract or
2020- otherwise, or (ii) ownership of fifty percent (50%) or more of the
2121- outstanding shares, or (iii) beneficial ownership of such entity.
2222-2323- "You" (or "Your") shall mean an individual or Legal Entity
2424- exercising permissions granted by this License.
2525-2626- "Source" form shall mean the preferred form for making modifications,
2727- including but not limited to software source code, documentation
2828- source, and configuration files.
2929-3030- "Object" form shall mean any form resulting from mechanical
3131- transformation or translation of a Source form, including but
3232- not limited to compiled object code, generated documentation,
3333- and conversions to other media types.
3434-3535- "Work" shall mean the work of authorship, whether in Source or
3636- Object form, made available under the License, as indicated by a
3737- copyright notice that is included in or attached to the work
3838- (an example is provided in the Appendix below).
3939-4040- "Derivative Works" shall mean any work, whether in Source or Object
4141- form, that is based on (or derived from) the Work and for which the
4242- editorial revisions, annotations, elaborations, or other modifications
4343- represent, as a whole, an original work of authorship. For the purposes
4444- of this License, Derivative Works shall not include works that remain
4545- separable from, or merely link (or bind by name) to the interfaces of,
4646- the Work and Derivative Works thereof.
4747-4848- "Contribution" shall mean any work of authorship, including
4949- the original version of the Work and any modifications or additions
5050- to that Work or Derivative Works thereof, that is intentionally
5151- submitted to Licensor for inclusion in the Work by the copyright owner
5252- or by an individual or Legal Entity authorized to submit on behalf of
5353- the copyright owner. For the purposes of this definition, "submitted"
5454- means any form of electronic, verbal, or written communication sent
5555- to the Licensor or its representatives, including but not limited to
5656- communication on electronic mailing lists, source code control systems,
5757- and issue tracking systems that are managed by, or on behalf of, the
5858- Licensor for the purpose of discussing and improving the Work, but
5959- excluding communication that is conspicuously marked or otherwise
6060- designated in writing by the copyright owner as "Not a Contribution."
6161-6262- "Contributor" shall mean Licensor and any individual or Legal Entity
6363- on behalf of whom a Contribution has been received by Licensor and
6464- subsequently incorporated within the Work.
6565-6666- 2. Grant of Copyright License. Subject to the terms and conditions of
6767- this License, each Contributor hereby grants to You a perpetual,
6868- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
6969- copyright license to reproduce, prepare Derivative Works of,
7070- publicly display, publicly perform, sublicense, and distribute the
7171- Work and such Derivative Works in Source or Object form.
7272-7373- 3. Grant of Patent License. Subject to the terms and conditions of
7474- this License, each Contributor hereby grants to You a perpetual,
7575- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
7676- (except as stated in this section) patent license to make, have made,
7777- use, offer to sell, sell, import, and otherwise transfer the Work,
7878- where such license applies only to those patent claims licensable
7979- by such Contributor that are necessarily infringed by their
8080- Contribution(s) alone or by combination of their Contribution(s)
8181- with the Work to which such Contribution(s) was submitted. If You
8282- institute patent litigation against any entity (including a
8383- cross-claim or counterclaim in a lawsuit) alleging that the Work
8484- or a Contribution incorporated within the Work constitutes direct
8585- or contributory patent infringement, then any patent licenses
8686- granted to You under this License for that Work shall terminate
8787- as of the date such litigation is filed.
8888-8989- 4. Redistribution. You may reproduce and distribute copies of the
9090- Work or Derivative Works thereof in any medium, with or without
9191- modifications, and in Source or Object form, provided that You
9292- meet the following conditions:
9393-9494- (a) You must give any other recipients of the Work or
9595- Derivative Works a copy of this License; and
9696-9797- (b) You must cause any modified files to carry prominent notices
9898- stating that You changed the files; and
9999-100100- (c) You must retain, in the Source form of any Derivative Works
101101- that You distribute, all copyright, patent, trademark, and
102102- attribution notices from the Source form of the Work,
103103- excluding those notices that do not pertain to any part of
104104- the Derivative Works; and
105105-106106- (d) If the Work includes a "NOTICE" text file as part of its
107107- distribution, then any Derivative Works that You distribute must
108108- include a readable copy of the attribution notices contained
109109- within such NOTICE file, excluding those notices that do not
110110- pertain to any part of the Derivative Works, in at least one
111111- of the following places: within a NOTICE text file distributed
112112- as part of the Derivative Works; within the Source form or
113113- documentation, if provided along with the Derivative Works; or,
114114- within a display generated by the Derivative Works, if and
115115- wherever such third-party notices normally appear. The contents
116116- of the NOTICE file are for informational purposes only and
117117- do not modify the License. You may add Your own attribution
118118- notices within Derivative Works that You distribute, alongside
119119- or as an addendum to the NOTICE text from the Work, provided
120120- that such additional attribution notices cannot be construed
121121- as modifying the License.
122122-123123- You may add Your own copyright statement to Your modifications and
124124- may provide additional or different license terms and conditions
125125- for use, reproduction, or distribution of Your modifications, or
126126- for any such Derivative Works as a whole, provided Your use,
127127- reproduction, and distribution of the Work otherwise complies with
128128- the conditions stated in this License.
129129-130130- 5. Submission of Contributions. Unless You explicitly state otherwise,
131131- any Contribution intentionally submitted for inclusion in the Work
132132- by You to the Licensor shall be under the terms and conditions of
133133- this License, without any additional terms or conditions.
134134- Notwithstanding the above, nothing herein shall supersede or modify
135135- the terms of any separate license agreement you may have executed
136136- with Licensor regarding such Contributions.
137137-138138- 6. Trademarks. This License does not grant permission to use the trade
139139- names, trademarks, service marks, or product names of the Licensor,
140140- except as required for reasonable and customary use in describing the
141141- origin of the Work and reproducing the content of the NOTICE file.
142142-143143- 7. Disclaimer of Warranty. Unless required by applicable law or
144144- agreed to in writing, Licensor provides the Work (and each
145145- Contributor provides its Contributions) on an "AS IS" BASIS,
146146- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147147- implied, including, without limitation, any warranties or conditions
148148- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149149- PARTICULAR PURPOSE. You are solely responsible for determining the
150150- appropriateness of using or redistributing the Work and assume any
151151- risks associated with Your exercise of permissions under this License.
152152-153153- 8. Limitation of Liability. In no event and under no legal theory,
154154- whether in tort (including negligence), contract, or otherwise,
155155- unless required by applicable law (such as deliberate and grossly
156156- negligent acts) or agreed to in writing, shall any Contributor be
157157- liable to You for damages, including any direct, indirect, special,
158158- incidental, or consequential damages of any character arising as a
159159- result of this License or out of the use or inability to use the
160160- Work (including but not limited to damages for loss of goodwill,
161161- work stoppage, computer failure or malfunction, or any and all
162162- other commercial damages or losses), even if such Contributor
163163- has been advised of the possibility of such damages.
164164-165165- 9. Accepting Warranty or Additional Liability. While redistributing
166166- the Work or Derivative Works thereof, You may choose to offer,
167167- and charge a fee for, acceptance of support, warranty, indemnity,
168168- or other liability obligations and/or rights consistent with this
169169- License. However, in accepting such obligations, You may act only
170170- on Your own behalf and on Your sole responsibility, not on behalf
171171- of any other Contributor, and only if You agree to indemnify,
172172- defend, and hold each Contributor harmless for any liability
173173- incurred by, or claims asserted against, such Contributor by reason
174174- of your accepting any such warranty or additional liability.
175175-176176- END OF TERMS AND CONDITIONS
177177-178178- APPENDIX: How to apply the Apache License to your work.
179179-180180- To apply the Apache License to your work, attach the following
181181- boilerplate notice, with the fields enclosed by brackets "[]"
182182- replaced with your own identifying information. (Don't include
183183- the brackets!) The text should be enclosed in the appropriate
184184- comment syntax for the file format. We also recommend that a
185185- file or class name and description of purpose be included on the
186186- same "printed page" as the copyright notice for easier
187187- identification within third-party archives.
188188-189189- Copyright [yyyy] [name of copyright owner]
190190-191191- Licensed under the Apache License, Version 2.0 (the "License");
192192- you may not use this file except in compliance with the License.
193193- You may obtain a copy of the License at
194194-195195- http://www.apache.org/licenses/LICENSE-2.0
196196-197197- Unless required by applicable law or agreed to in writing, software
198198- distributed under the License is distributed on an "AS IS" BASIS,
199199- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200200- See the License for the specific language governing permissions and
201201- limitations under the License.
-21
safir-mem/LICENSE-MIT
···11-MIT License
22-33-Copyright (c) 2023 Graham Keenan
44-55-Permission is hereby granted, free of charge, to any person obtaining a copy
66-of this software and associated documentation files (the "Software"), to deal
77-in the Software without restriction, including without limitation the rights
88-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
99-copies of the Software, and to permit persons to whom the Software is
1010-furnished to do so, subject to the following conditions:
1111-1212-The above copyright notice and this permission notice shall be included in all
1313-copies or substantial portions of the Software.
1414-1515-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1616-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1717-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121-SOFTWARE.
-56
safir-mem/README.md
···11-# Safir-mem
22-33-## Notice
44-55-:warning: This is now archived and no longer updated :warning:
66-77-It was ambitious (and worked kinda) but became far too unweildy and complicated when it didn't have to.
88-Maybe a rewrite in the future but for now, it's now archived.
99-1010-Simple in-memory CLI key/value store.
1111-1212-The in-memory version of [Safir](https://crates.io/crates/safir)!
1313-1414-`safir-mem` starts a service which runs on `localhost` or `127.0.0.1` on dedicated port `9876`.
1515-1616-This can be enabled / diabled with the `start` and `stop` commands respectively.
1717-Note that when the memcache service is disabled, ALL data contained within it is lost so use wisely.
1818-1919-In cases where you want to save the contents of the memcache, the `dump` command will allow for the contents to be saved out to disk in JSON format.
2020-This behaves as a snapshot as the contents of the cache persist after usage.
2121-2222-## Install
2323-2424-To install `safir-mem`, run `cargo install safir-mem`.
2525-2626-### Requirements
2727-2828-Using this requires that the [Rubin CLI](https://crates.io/crates/rubin-cli) be installed.
2929-3030-```bash
3131-cargo install rubin-cli
3232-```
3333-3434-## Usage
3535-3636-```bash
3737-In-memory key/value store to share information between shell sessions
3838-3939-Usage: safir-mem <COMMAND>
4040-4141-Commands:
4242- add Add a value to the store with the given key
4343- get Get a value from the store
4444- rm Remove values from the store
4545- alias Output the alias command for a key / value pair to be entered into a shell session
4646- export Output the export command for a key / value pair to be entered into a shell session
4747- clear Clear all keys/values from the store
4848- start Start the memcache server
4949- stop Stop the memcache server
5050- dump Dump contents of memcache to disk
5151- help Print this message or the help of the given subcommand(s)
5252-5353-Options:
5454- -h, --help Print help
5555- -V, --version Print version
5656-```
-85
safir-mem/src/cli.rs
···11-//! CLI for using the Safir binary
22-pub use clap::{Args, Parser, Subcommand};
33-44-/// CLI arguments for running the program
55-#[derive(Parser, Debug)]
66-#[command(author, version)]
77-#[command(propagate_version = true)]
88-#[command(about = "In-memory key/value store to share information between shell sessions", long_about = None)]
99-pub struct Cli {
1010- /// Subcommands
1111- #[command(subcommand)]
1212- pub command: Commands,
1313-}
1414-1515-/// Subcommands for running the program
1616-#[derive(Subcommand, Debug, PartialEq)]
1717-pub enum Commands {
1818- /// Add a value to the store with the given key
1919- Add(AddArgs),
2020-2121- /// Get a value from the store
2222- Get(GetArgs),
2323-2424- /// Remove values from the store
2525- Rm(RemoveArgs),
2626-2727- /// Output the alias command for a key / value pair to be entered into a shell session
2828- Alias(SetArgs),
2929-3030- /// Output the export command for a key / value pair to be entered into a shell session
3131- Export(SetArgs),
3232-3333- /// Clear all keys/values from the store
3434- Clear,
3535-3636- /// Start the memcache server
3737- Start,
3838-3939- /// Stop the memcache server
4040- Stop,
4141-4242- /// Dump contents of memcache to disk
4343- Dump(DumpArgs),
4444-}
4545-4646-/// Arguments for adding a value to the store with a given key
4747-#[derive(Args, Debug, PartialEq)]
4848-pub struct AddArgs {
4949- /// Name of the item to store
5050- pub key: String,
5151-5252- /// Value to store
5353- pub value: String,
5454-}
5555-5656-/// Arguments for retrieving a value from the store with a given key
5757-#[derive(Args, Debug, PartialEq)]
5858-pub struct GetArgs {
5959- /// Name of the value to retrieve from the store
6060- ///
6161- /// Returns nothing if the key does not exist
6262- pub key: Option<String>,
6363-}
6464-6565-/// Arguments for removing values from the store with given keys
6666-#[derive(Args, Debug, PartialEq)]
6767-pub struct RemoveArgs {
6868- /// Name of the keys to remove from the store
6969- ///
7070- /// Does nothing if the keys do not exist
7171- pub key: Vec<String>,
7272-}
7373-7474-/// Arguments for outputting commands with a given prefix
7575-#[derive(Args, Debug, PartialEq)]
7676-pub struct SetArgs {
7777- /// Name of the keys to display (e.g. alias / export)
7878- pub keys: Vec<String>,
7979-}
8080-8181-#[derive(Args, Debug, PartialEq)]
8282-pub struct DumpArgs {
8383- /// Path to save the store to
8484- pub path: String,
8585-}
-108
safir-mem/src/main.rs
···11-mod cli;
22-33-use cli::*;
44-use safir_core::{utils, Safir, SafirEngineType};
55-66-use anyhow::Result;
77-use std::process::{Command, Stdio};
88-99-#[tokio::main]
1010-async fn main() -> Result<()> {
1111- let cli = Cli::parse();
1212- let mut safir_mem = Safir::new(SafirEngineType::Memcache).await?;
1313-1414- match &cli.command {
1515- Commands::Add(args) => {
1616- safir_mem
1717- .add_entry(args.key.to_owned(), args.value.to_owned())
1818- .await?
1919- }
2020- Commands::Get(args) => {
2121- if let Some(key) = &args.key {
2222- safir_mem.get_entry(key.to_string()).await?;
2323- } else {
2424- println!("A key is required for memcache GET command!");
2525- }
2626- }
2727- Commands::Rm(args) => {
2828- safir_mem.remove_entry(args.key.clone()).await?;
2929- }
3030- Commands::Alias(args) => {
3131- safir_mem.set_commands("alias", &args.keys).await;
3232- }
3333- Commands::Export(args) => {
3434- safir_mem.set_commands("export", &args.keys).await;
3535- }
3636- Commands::Clear => {
3737- safir_mem.clear_entries().await?;
3838- }
3939- Commands::Start => {
4040- if !utils::check_rubin_installed() {
4141- eprintln!(
4242- "The Rubin binary must be installed to use this feature, please install it via cargo using `cargo install rubin-cli`"
4343- );
4444- return Ok(());
4545- }
4646-4747- let config = &mut safir_mem.config;
4848- if let Some(pid) = config.memcache_pid {
4949- println!(
5050- "Safir memcache service is already running on 127.0.0.1:9876 - PID {}",
5151- pid
5252- );
5353-5454- return Ok(());
5555- }
5656-5757- let child = Command::new("rubin")
5858- .args(["server"])
5959- .stdout(Stdio::null())
6060- .stderr(Stdio::null())
6161- .stdin(Stdio::null())
6262- .spawn()
6363- .expect("unable to spawn child process");
6464-6565- let pid = child.id();
6666- config.memcache_pid = Some(pid);
6767- config.write().await?;
6868- println!(
6969- "Safir memcache service started at 127.0.0.1:9876 - PID {}",
7070- pid
7171- );
7272- }
7373- Commands::Stop => {
7474- if !utils::check_rubin_installed() {
7575- eprintln!("The Rubin binary must be installed to use this feature, please install it via cargo using `cargo install rubin-cli`");
7676- return Ok(());
7777- }
7878-7979- let config = &mut safir_mem.config;
8080- let pid = match config.memcache_pid {
8181- Some(pid) => pid,
8282- None => {
8383- println!("Safir memcache service does not seem to be running.");
8484- return Ok(());
8585- }
8686- };
8787-8888- if let Err(err) = utils::kill_process(pid).await {
8989- eprintln!(
9090- "Safir memcache service failed to stop, manual removal may be necessary - {}",
9191- err
9292- );
9393- } else {
9494- config.memcache_pid = None;
9595- config.write().await?;
9696- println!("Stopping Safir memcache service!");
9797- }
9898- }
9999- Commands::Dump(args) => {
100100- let inner = safir_mem.as_safir_memcache();
101101- if let Err(e) = inner.dump_store(&args.path).await {
102102- eprintln!("unable to dump Safir memcache service: {}", e);
103103- }
104104- }
105105- }
106106-107107- Ok(())
108108-}
···11-# Safir
22-33-Simple CLI key/value store.
44-55-Store key/value pairs in the terminal and retrieve them later for use like in different shell sessions.
66-77-## Install
88-99-To install `safir`, run `cargo install safir`.
1010-1111-To build from source, clone the repository and run:
1212-1313-```bash
1414-cargo build --release
1515-```
1616-1717-Then move the binary to somewhere in your `$PATH`
1818-1919-## Usage
2020-2121-When `safir` is run, it creates a store file in your `$HOME` directory (`$HOME/.safirstore/safirstore.json`).
2222-2323-Run `safir --help` for usage:
2424-2525-```bash
2626-Key/Value store to share information between shell sessions
2727-2828-Usage: safir <COMMAND>
2929-3030-Commands:
3131- add Add a value to the store with the given key
3232- get Get values from the store
3333- rm Remove values from the store
3434- alias Output the alias command for key / value pairs
3535- export Output the export command for a key / value pairs
3636- list List all values in the store
3737- clear Clear all keys/values from the store
3838- purge Purges the .safirstore directory, removing it and its contents
3939- help Print this message or the help of the given subcommand(s)
4040-4141-Options:
4242- -h, --help Print help
4343- -V, --version Print version
4444-```
4545-4646-## Examples
4747-4848-Adding a key and value to the store:
4949-5050-```bash
5151-safir add api_key "api_key_value"
5252-```
5353-5454-Retrieving a value from the store:
5555-5656-```bash
5757-safir get api_key
5858-# api_key="api_key_value"
5959-```
6060-6161-Removing a value from the store:
6262-6363-```bash
6464-safir rm api_key
6565-```
6666-6767-List all values in the store:
6868-6969-```bash
7070-safir list
7171-7272-# api_key="api_key_value"
7373-# another_api_key="another_value"
7474-```
7575-7676-Exporting a value:
7777-7878-```bash
7979-safir export api_key
8080-# export api_key="api_key_value"
8181-8282-$(safir export api_key) # <-- Will export the value to the current shell
8383-```
8484-8585-Aliasing a value:
8686-8787-```bash
8888-safir alias long_command
8989-# alias long_command="cd build/ && make && sudo make install"
9090-9191-$(safir alias long_command) # <-- Will alias the command in the current shell
9292-```
9393-9494-Clear the store:
9595-9696-```bash
9797-safir clear
9898-# Will remove all contents in the store
9999-```
100100-101101-Purge the store (remove EVERYTHING `safir` related)
102102-103103-```bash
104104-safir purge # Will remove the .safirstore directory
105105-```