Browse Source

Wayland support, remove exponential keyring build, fix tmpfile creation.

tags/v0.3.5
Thomas Kerber 4 months ago
parent
commit
053b5fa1bf
Signed by: tk <tk@drwx.org> GPG Key ID: 8489B911F9ED617B
22 changed files with 3736 additions and 860 deletions
  1. +628
    -89
      Cargo.lock
  2. +460
    -214
      Cargo.nix
  3. +8
    -4
      Cargo.toml
  4. +71
    -17
      crates-io.list
  5. +2420
    -487
      crates-io.nix
  6. +18
    -2
      default.nix
  7. +2
    -2
      goblin-core/Cargo.toml
  8. +2
    -2
      goblin-core/src/err.rs
  9. +18
    -2
      goblin-core/src/format.rs
  10. +3
    -1
      goblin-core/src/ipc/mod.rs
  11. +18
    -6
      goblin-core/src/keyring.rs
  12. +11
    -9
      goblin-core/src/state.rs
  13. +7
    -3
      src/args.rs
  14. +16
    -9
      src/cmd/copy.rs
  15. +1
    -2
      src/cmd/generate.rs
  16. +2
    -2
      src/cmd/log.rs
  17. +1
    -0
      src/cmd/mod.rs
  18. +21
    -4
      src/err.rs
  19. +11
    -2
      src/main.rs
  20. +1
    -1
      src/term.rs
  21. +14
    -1
      src/util.rs
  22. +3
    -1
      update.sh

+ 628
- 89
Cargo.lock
File diff suppressed because it is too large
View File


+ 460
- 214
Cargo.nix
File diff suppressed because it is too large
View File


+ 8
- 4
Cargo.toml View File

@@ -1,21 +1,25 @@
[package]
name = "goblin"
version = "0.3.4"
version = "0.3.5"
authors = ["Thomas Kerber <tk@drwx.org>"]
description = "Version controlled password management."
publish = false

[features]
default_features = []
default = []
weak-scrypt = ["goblin-core/weak-scrypt"]
copy = ["clipboard"]
copy-wayland = ["wl-clipboard-rs", "failure"]

[dependencies]
clap = "2.33"
clipboard = "0.5"
clipboard = { version = "0.5", optional = true }
wl-clipboard-rs = { version = "0.4", optional = true }
failure = { version = "0.1", optional = true }
getch = "0.2"
goblin-core = { path = "goblin-core" }
log = { version = "0.4", features = ["release_max_level_info"] }
rand = "0.6"
rand = "0.7"
rpassword = "3"
term = "0.5"
atty = "0.2"


+ 71
- 17
crates-io.list View File

@@ -1,20 +1,20 @@
aho-corasick-0.7.6
aho-corasick-0.6.10
ansi_term-0.11.0
arrayref-0.3.5
arrayvec-0.5.1
atty-0.2.13
atty-0.2.11
autocfg-0.1.7
backtrace-0.3.40
backtrace-sys-0.1.32
base64-0.10.1
bitflags-0.7.0
bitflags-1.2.1
blake2b_simd-0.5.9
blake2b_simd-0.5.10
block-0.1.6
bstr-0.2.8
byteorder-1.3.2
bytes-0.4.12
cc-1.0.47
c2-chacha-0.2.3
cc-1.0.50
cfg-if-0.1.10
chrono-0.4.10
clap-2.33.0
@@ -28,10 +28,15 @@ crossbeam-queue-0.1.2
crossbeam-utils-0.6.6
crossbeam-utils-0.7.0
cstr-argument-0.1.1
derive-new-0.5.8
derive_more-0.99.2
dirs-1.0.5
downcast-rs-1.1.1
exitfailure-0.5.1
failure-0.1.6
failure_derive-0.1.6
filetime-0.2.8
fixedbitset-0.1.9
fnv-1.0.6
fuchsia-cprng-0.1.1
fuchsia-zircon-0.3.3
@@ -39,8 +44,10 @@ fuchsia-zircon-sys-0.3.3
futures-0.1.29
gcrypt-0.6.1
getch-0.2.1
globset-0.4.4
getrandom-0.1.14
globset-0.4.1
gpg-error-0.4.1
heck-0.3.1
hermit-abi-0.1.3
hex-0.2.0
idna-0.1.5
@@ -52,6 +59,7 @@ jsonrpc-macros-10.1.0
jsonrpc-pubsub-10.1.0
jsonrpc-server-utils-10.1.0
kernel32-sys-0.2.2
lazy_static-0.2.11
lazy_static-1.4.0
libc-0.2.66
libgcrypt-sys-0.6.1
@@ -59,13 +67,15 @@ libgpg-error-sys-0.4.1
libssh2-sys-0.2.13
libz-sys-1.0.25
lock_api-0.1.5
lock_api-0.3.2
lock_api-0.3.3
log-0.4.8
malloc_buf-0.0.6
matches-0.1.8
maybe-uninit-2.0.0
memchr-2.2.1
memoffset-0.5.3
mime-0.3.16
mime_guess-2.0.1
mio-0.6.21
mio-named-pipes-0.1.6
mio-uds-0.6.7
@@ -73,30 +83,49 @@ miow-0.2.1
miow-0.3.3
net2-0.2.33
nix-0.13.1
nix-0.14.1
nix-0.16.1
nom-2.2.1
num-integer-0.1.41
num-traits-0.2.10
num_cpus-1.11.1
numtoa-0.1.0
objc-0.2.7
objc-foundation-0.1.1
objc_id-0.1.1
openssl-sys-0.9.53
ordermap-0.3.5
os_pipe-0.9.1
owning_ref-0.3.3
owning_ref-0.4.0
parity-tokio-ipc-0.1.0
parking_lot-0.4.8
parking_lot-0.7.1
parking_lot-0.9.0
parking_lot_core-0.2.14
parking_lot_core-0.4.0
parking_lot_core-0.6.2
percent-encoding-1.0.1
petgraph-0.4.13
pkg-config-0.3.17
proc-macro2-1.0.6
ppv-lite86-0.2.6
proc-macro-error-0.4.4
proc-macro-error-attr-0.4.3
proc-macro2-0.4.30
proc-macro2-1.0.7
quote-0.6.13
quote-1.0.2
rand-0.3.23
rand-0.4.6
rand-0.6.5
rand-0.7.2
rand_chacha-0.1.1
rand_chacha-0.2.1
rand_core-0.3.1
rand_core-0.4.2
rand_core-0.5.1
rand_hc-0.1.0
rand_hc-0.2.0
rand_isaac-0.1.1
rand_jitter-0.1.4
rand_os-0.1.3
@@ -104,37 +133,47 @@ rand_pcg-0.1.2
rand_xorshift-0.1.1
rdrand-0.4.0
redox_syscall-0.1.56
redox_termios-0.1.1
redox_users-0.3.1
regex-1.3.1
regex-1.0.2
regex-syntax-0.6.12
remove_dir_all-0.5.2
rpassword-3.0.2
rust-argon2-0.5.1
rustc-demangle-0.1.16
rustc_version-0.2.3
rustversion-1.0.1
ryu-1.0.2
scopeguard-0.3.3
scopeguard-1.0.0
semver-0.9.0
semver-parser-0.7.0
serde-1.0.103
serde_derive-1.0.103
serde_json-1.0.42
serde-1.0.104
serde_derive-1.0.104
serde_json-1.0.44
slab-0.4.2
smallvec-0.6.13
smallvec-1.0.0
smallvec-1.1.0
socket2-0.3.11
ssh2-0.3.3
stable_deref_trait-1.1.1
stderrlog-0.4.3
strsim-0.8.0
syn-1.0.11
structopt-0.3.7
structopt-derive-0.4.0
syn-1.0.13
syn-mid-0.4.0
synstructure-0.12.3
tar-0.4.26
tempdir-0.3.7
tempfile-3.1.0
term-0.5.2
term_size-0.3.1
termcolor-1.0.5
termion-1.5.4
termios-0.2.2
textwrap-0.11.0
thread_local-0.3.6
thread_local-0.3.4
time-0.1.42
tokio-0.1.22
tokio-codec-0.1.1
@@ -147,28 +186,43 @@ tokio-reactor-0.1.11
tokio-service-0.1.0
tokio-sync-0.1.7
tokio-tcp-0.1.3
tokio-threadpool-0.1.16
tokio-threadpool-0.1.17
tokio-timer-0.2.12
tokio-udp-0.1.5
tokio-uds-0.2.5
tree_magic-0.2.1
unicase-2.6.0
unicode-bidi-0.3.4
unicode-normalization-0.1.11
unicode-width-0.1.6
unicode-segmentation-1.6.0
unicode-width-0.1.7
unicode-xid-0.1.0
unicode-xid-0.2.0
unreachable-1.0.0
url-1.7.2
users-0.9.1
utf8-ranges-1.0.4
vcpkg-0.2.8
vec_map-0.8.1
version_check-0.9.1
void-1.0.2
wasi-0.9.0+wasi-snapshot-preview1
wayland-client-0.23.6
wayland-commons-0.23.6
wayland-protocols-0.23.6
wayland-scanner-0.23.6
wayland-sys-0.23.6
winapi-0.2.8
winapi-0.3.8
winapi-build-0.1.1
winapi-i686-pc-windows-gnu-0.4.0
winapi-util-0.1.2
winapi-x86_64-pc-windows-gnu-0.4.0
wincolor-1.0.2
wl-clipboard-rs-0.4.0
ws2_32-sys-0.2.1
x11-clipboard-0.3.3
xattr-0.2.2
xcb-0.8.2
xdg-2.2.0
xml-rs-0.8.0

+ 2420
- 487
crates-io.nix
File diff suppressed because it is too large
View File


+ 18
- 2
default.nix View File

@@ -1,8 +1,24 @@
{ pkgs ? import <nixpkgs> { }}:
{ pkgs ? import <nixpkgs> { }, clipboard ? false, wayland-clipboard ? false }:
with pkgs;

((callPackage ./Cargo.nix { }).goblin { }).override {
let
cargo = callPackage ./Cargo.nix { };
in (cargo.goblin {
features = cargo.crates.features_.goblin."0.3.5" cargo.deps {
goblin."0.3.5".copy = clipboard;
goblin."0.3.5".copy-wayland = wayland-clipboard;
"tree_magic"."0.2.1"."cli" = false;
};
}).override {
crateOverrides = defaultCrateOverrides // {
wayland-protocols = attrs: {
CARGO_FEATURE_CLIENT = "1";
CARGO_FEATURE_SERVER = "1";
CARGO_FEATURE_UNSTABLE_PROTOCOLS = "1";
postFixup = ''
rm $lib/env
'';
};
libgpg-error-sys = attrs: {
postFixup = ''
substituteInPlace $lib/env --replace LIBGPG-ERROR GPG_ERROR


+ 2
- 2
goblin-core/Cargo.toml View File

@@ -1,6 +1,6 @@
[package]
name = "goblin-core"
version = "0.3.4"
version = "0.3.5"
authors = ["Thomas Kerber <tk@drwx.org>"]
publish = false

@@ -18,7 +18,7 @@ jsonrpc-core = {version="10.0", optional=true}
jsonrpc-ipc-server = {version="10.0", optional=true}
jsonrpc-macros = {version="10.0", optional=true}
log = {version="0.4", features=["release_max_level_debug"]}
rand = {version="0.6", optional=true}
rand = {version="0.7", optional=true}
serde = "1"
serde_derive = "1"
serde_json = "1"


+ 2
- 2
goblin-core/src/err.rs View File

@@ -193,7 +193,7 @@ impl<T> From<PoisonError<T>> for Error {
impl StdError for Error {
fn description(&self) -> &str {
match self {
&Gcrypt(ref e) => (e as &StdError).description(),
&Gcrypt(ref e) => (e as &dyn StdError).description(),
&Io(ref e) => e.description(),
&Serde(ref e) => e.description(),
&InvalidHash(s) => s,
@@ -234,7 +234,7 @@ impl StdError for Error {
}
}

fn cause(&self) -> Option<&StdError> {
fn cause(&self) -> Option<&dyn StdError> {
match self {
&Gcrypt(ref e) => Some(e),
&Io(ref e) => Some(e),


+ 18
- 2
goblin-core/src/format.rs View File

@@ -13,6 +13,8 @@ use std::ffi::OsStr;
use std::io::{self, Cursor, Read};
use std::mem::replace;
use std::ops::{Deref, DerefMut};
use std::cmp::{PartialEq, Eq};
use std::hash::{Hash as StdHash, Hasher};
use std::result::Result as StdResult;
use std::str::FromStr;
use std::time::SystemTime;
@@ -446,6 +448,20 @@ pub struct Commit {
pub hash: Option<Hash>,
}

impl PartialEq for Commit {
fn eq(&self, other: &Self) -> bool {
self.hash == other.hash
}
}

impl Eq for Commit { }

impl StdHash for Commit {
fn hash<H: Hasher>(&self, state: &mut H) {
self.hash.hash(state);
}
}

impl Commit {
/// Creates a new commit with the head as its predecessor.
#[allow(missing_docs)]
@@ -498,10 +514,10 @@ impl Commit {
let mut enc = Vec::new();
encrypt(data, vault.key.as_ref().unwrap(), &mut enc)?;
self.hash = Some(Hash::new(&enc[..]));
let path = format!("{}.commit", self.hash()?);
let path = format!("{}.commit", Commit::hash(self)?);
vault.memtar.create(&path, enc)?;
vault.modified = true;
vault.metadata.head = Some(self.hash()?);
vault.metadata.head = Some(Commit::hash(self)?);
vault.write_metadata()?;
info!("created new commit {:?}", path);
Ok(())


+ 3
- 1
goblin-core/src/ipc/mod.rs View File

@@ -107,7 +107,9 @@ impl Client {
let path = if xdg.has_runtime_directory() {
xdg.create_runtime_directory("goblin")?
} else {
PathBuf::from(format!("/tmp/goblin.{}", getuid()))
let path = PathBuf::from(format!("/tmp/goblin.{}", getuid()));
create_dir_all(&path)?;
path
};
for sock in read_dir(path)? {
if let Ok(Some(cli)) = sock.map_err(Error::from)


+ 18
- 6
goblin-core/src/keyring.rs View File

@@ -4,7 +4,7 @@ use format::{Commit, Delta, Vault};
use hex::{FromHex, ToHex};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::collections::{HashMap, BTreeMap};
use std::fmt::{self, Debug, Display};
use std::mem::replace;
use std::result::Result as StdResult;
@@ -158,22 +158,31 @@ impl Keyring {
pub fn from_vault(vault: &Vault) -> Result<Self> {
info!("constructing keyring");
if let Some(i) = vault.head_commit()? {
Keyring::from_commit(vault, i)
let mut cache = HashMap::new();
Keyring::from_commit(vault, i, &mut cache)
} else {
Ok(Self::empty())
}
}

#[allow(missing_docs)]
pub fn from_hash(vault: &Vault, hash: Hash) -> Result<Self> {
Self::from_commit(vault, vault.commit(hash)?)
pub fn from_hash(
vault: &Vault,
hash: Hash,
cache: &mut HashMap<Commit, Keyring>
) -> Result<Self> {
Self::from_commit(vault, vault.commit(hash)?, cache)
}

#[allow(missing_docs)]
pub fn from_commit<'a>(
vault: &'a Vault,
mut commit: &'a Commit,
cache: &'a mut HashMap<Commit, Keyring>,
) -> Result<Self> {
if let Some(kr) = cache.get(commit) {
return Ok(kr.clone());
}
debug!("constructing keyring from commit {}", commit.hash()?);
let mut hist_chain = vec![];
let mut previous = commit.previous(vault)?;
@@ -187,13 +196,15 @@ impl Keyring {
Keyring(BTreeMap::new())
} else {
debug!("commit {} is a merge", commit.hash()?);
let (mut kr, sec) = Keyring::start_merge(vault, previous)?;
let (mut kr, sec) = Keyring::start_merge(vault, previous, cache)?;
kr.replay(commit);
kr.finish_merge(sec);
cache.insert(commit.clone(), kr.clone());
kr
};
while let Some(commit) = hist_chain.pop() {
kr.replay(commit);
cache.insert(commit.clone(), kr.clone());
}
Ok(kr)
}
@@ -207,6 +218,7 @@ impl Keyring {
pub fn start_merge(
vault: &Vault,
commits: Vec<&Commit>,
cache: &mut HashMap<Commit, Keyring>,
) -> Result<(Self, Vec<Hash>)> {
if commits.len() < 1 {
return Err(Error::InvalidMerge);
@@ -224,7 +236,7 @@ impl Keyring {
for commit in commits {
previous_keyrings.push((
commit.hash()?,
Keyring::from_commit(vault, commit)?,
Keyring::from_commit(vault, commit, cache)?,
));
}
debug!("recursively reconstructing and renaming");


+ 11
- 9
goblin-core/src/state.rs View File

@@ -6,7 +6,7 @@ use keyring::{Entry, Keyring, Path, Value};
use location::VaultLocation;
use perm::{Access, AccessControl, Permissions, Scope, UnlockSpec};
use std::borrow::{Borrow, Cow};
use std::collections::HashSet;
use std::collections::{HashSet, HashMap};
use std::io;
use std::mem::replace;
use std::result::Result as StdResult;
@@ -221,7 +221,8 @@ impl VaultState {
// This IS NOT an error. A blank static state is returned.
None => return (Static(vault.into(), Keyring::empty()), Ok(())),
};
match Keyring::from_hash(vault.borrow(), hash) {
let mut cache = HashMap::new();
match Keyring::from_hash(vault.borrow(), hash, &mut cache) {
Ok(kr) => {
if Some(hash) != head {
(Detached(vault.into(), kr, hash), Ok(()))
@@ -542,7 +543,7 @@ impl KeyringState {
Ok(())
}

fn as_dirty_state(&mut self) -> Result<&mut Dirty> {
fn as_dirty_state(&mut self) -> Result<&mut dyn Dirty> {
match self {
&mut Locked => Err(Error::Locked),
&mut Static(..) => Err(Error::ReadOnly),
@@ -742,6 +743,7 @@ impl Merge {
None
})));
}
let mut cache = HashMap::new();
let kr = match {
hashes
.iter()
@@ -751,7 +753,7 @@ impl Merge {
commits.push(commit?);
Ok(commits)
})
.and_then(|commits| Keyring::start_merge(&vault, commits))
.and_then(|commits| Keyring::start_merge(&vault, commits, &mut cache))
} {
Ok((kr, _)) => kr,
Err(e) => return Err((vault, e)),
@@ -764,7 +766,7 @@ impl Merge {
deltas: Vec::new(),
};
let conflicts = if auto && merge.predecessors.len() == 2 {
let conflicts = match merge.automerge() {
let conflicts = match merge.automerge(&mut cache) {
Ok(v) => v,
Err(e) => return Err((merge.vault, e)),
};
@@ -819,7 +821,7 @@ impl Merge {
)
}

fn automerge(&mut self) -> Result<Vec<Path>> {
fn automerge(&mut self, cache: &mut HashMap<Commit, Keyring>) -> Result<Vec<Path>> {
// Should never be called otherwise!
assert!(self.predecessors.len() == 2);
info!(
@@ -832,13 +834,13 @@ impl Merge {
// FIXME: this fails.
let ancestor =
if let Some(anc) = self.vault.idom_mult(&self.predecessors[..])? {
Keyring::from_commit(&self.vault, self.vault.commit(anc)?)?
Keyring::from_commit(&self.vault, self.vault.commit(anc)?, cache)?
} else {
warn!("commits to merge do not share a commit ancestor!");
Keyring::empty()
};
let primary = Keyring::from_hash(&self.vault, self.predecessors[0])?;
let secondary = Keyring::from_hash(&self.vault, self.predecessors[1])?;
let primary = Keyring::from_hash(&self.vault, self.predecessors[0], cache)?;
let secondary = Keyring::from_hash(&self.vault, self.predecessors[1], cache)?;
let mut paths = Vec::<&Path>::new();
for kr in &[&primary, &secondary, &ancestor] {
paths.extend(&kr.keys()[..])


+ 7
- 3
src/args.rs View File

@@ -1,8 +1,9 @@
use clap::{App, AppSettings, Arg, ArgGroup, SubCommand};
use std::str::FromStr;

#[allow(unused_mut)]
pub fn goblin() -> App<'static, 'static> {
App::new(crate_name!())
let mut app = App::new(crate_name!())
.version(crate_version!())
.author(crate_authors!())
.about("Version controlled password management.")
@@ -13,7 +14,6 @@ pub fn goblin() -> App<'static, 'static> {
.subcommand(unlock())
.subcommand(lock())
.subcommand(echo())
.subcommand(copy())
.subcommand(insert())
.subcommand(import())
.subcommand(which())
@@ -31,7 +31,11 @@ pub fn goblin() -> App<'static, 'static> {
.subcommand(commit())
.subcommand(discard())
.subcommand(generate())
.subcommand(sync())
.subcommand(sync());
if cfg!(any(feature = "copy", feature = "copy-wayland")) {
app = app.subcommand(copy());
}
app
}

pub fn daemon() -> App<'static, 'static> {


+ 16
- 9
src/cmd/copy.rs View File

@@ -17,17 +17,24 @@ pub fn main(matches: &ArgMatches) -> Result<()> {
path = cli.call("goblin.keyring.find", (&path,))?;
}
let val: String = cli.call("goblin.keyring.get", (&path,))?;
copy(val)?;
if cfg.verbosity >= 0 {
println!("Value {} copied. Press any key to wipe.", path.bold());
if cfg!(feature = "copy") {
println!("Value {} copied. Press any key to wipe.", path.bold());
} else if cfg!(feature = "copy-wayland") {
println!("Value {} will be copied, and wiped after one paste.", path.bold());
}
}
// FIXME: properly support --non-interactive
// Copy doesn't outlive goblin due to clipboard crate limitations, this
// suits us perfectly.
init_timeout();
Getch::new().getch()?;
if cfg.verbosity >= 0 {
println!("Value wiped.");
copy(val)?;
#[cfg(feature = "copy")]
{
// FIXME: properly support --non-interactive
// Copy doesn't outlive goblin due to clipboard crate limitations, this
// suits us perfectly.
init_timeout();
Getch::new().getch()?;
if cfg.verbosity >= 0 {
println!("Value wiped.");
}
}
Ok(())
}

+ 1
- 2
src/cmd/generate.rs View File

@@ -42,14 +42,13 @@ pub fn main(matches: &ArgMatches) -> Result<()> {
}
pool.sort();
pool.dedup();
let mut rng = OsRng::new()?;
let len = if let Some(l) = matches.value_of("LENGTH") {
l.parse::<usize>().unwrap()
} else {
20
};
let pass: String =
(0..len).map(|_| pool[..].choose(&mut rng).unwrap()).collect();
(0..len).map(|_| pool[..].choose(&mut OsRng).unwrap()).collect();
if let Some(path) = matches.value_of("PATH") {
let mut cli = require_client(&cfg)?;
let value = Value::new(pass.into());


+ 2
- 2
src/cmd/log.rs View File

@@ -10,11 +10,11 @@ use term::Stylable;
use util::{ClientExt, print_delta, require_client};

trait HashExt {
fn optlong(self, long: bool) -> Box<Display>;
fn optlong(self, long: bool) -> Box<dyn Display>;
}

impl HashExt for Hash {
fn optlong(self, long: bool) -> Box<Display> {
fn optlong(self, long: bool) -> Box<dyn Display> {
if long {
Box::new(self)
} else {


+ 1
- 0
src/cmd/mod.rs View File

@@ -1,3 +1,4 @@
#[cfg(any(feature = "copy", feature = "copy-wayland"))]
pub mod copy;
pub mod create;
pub mod daemon;


+ 21
- 4
src/err.rs View File

@@ -6,6 +6,10 @@ use std::error::Error as StdError;
use std::fmt::{self, Display};
use std::io;
use std::result::Result as StdResult;
#[cfg(feature = "copy-wayland")]
use wl_clipboard_rs::copy::Error as CopyError;
#[cfg(feature = "copy-wayland")]
use failure::{Compat, Fail};

pub type Result<T> = StdResult<T, Error>;

@@ -24,13 +28,15 @@ pub enum Error {
Io(io::Error),
ExecutableUnknown,
ConnectTimeout,
Boxed(Box<StdError>),
Boxed(Box<dyn StdError>),
NonInteractivePassword,
Generic(String),
PasswordMismatch,
AutomergeFailed,
Json(serde_json::Error),
Rand(rand::Error),
#[cfg(feature = "copy-wayland")]
Copy(Compat<CopyError>),
}

impl From<serde_json::Error> for Error {
@@ -51,8 +57,8 @@ impl From<io::Error> for Error {
}
}

impl From<Box<StdError>> for Error {
fn from(e: Box<StdError>) -> Error {
impl From<Box<dyn StdError>> for Error {
fn from(e: Box<dyn StdError>) -> Error {
Error::Boxed(e)
}
}
@@ -63,6 +69,13 @@ impl From<rand::Error> for Error {
}
}

#[cfg(feature = "copy-wayland")]
impl From<CopyError> for Error {
fn from(e: CopyError) -> Error {
Error::Copy(e.compat())
}
}

impl StdError for Error {
fn description(&self) -> &str {
match self {
@@ -81,16 +94,20 @@ impl StdError for Error {
}
&Json(ref e) => e.description(),
&Rand(ref e) => e.description(),
#[cfg(feature = "copy-wayland")]
&Copy(ref e) => e.description(),
}
}

fn cause(&self) -> Option<&StdError> {
fn cause(&self) -> Option<&dyn StdError> {
match self {
&Core(ref e) => Some(e),
&Io(ref e) => Some(e),
&Boxed(ref e) => Some(&**e),
&Json(ref e) => Some(e),
&Rand(ref e) => Some(e),
#[cfg(feature = "copy-wayland")]
&Copy(ref e) => Some(e),
_ => None,
}
}


+ 11
- 2
src/main.rs View File

@@ -6,7 +6,12 @@ extern crate term as term_crate;
#[macro_use]
extern crate log as log_crate;
extern crate rpassword;
#[cfg(feature = "copy")]
extern crate clipboard;
#[cfg(feature = "copy-wayland")]
extern crate wl_clipboard_rs;
#[cfg(feature = "copy-wayland")]
extern crate failure;
extern crate getch;
extern crate atty;
extern crate serde_json;
@@ -46,13 +51,13 @@ fn main() {
}
}

#[allow(unused_mut)]
fn main_err(matches: &ArgMatches) -> Result<()> {
let subcmds = cmds!(
let mut subcmds = cmds!(
daemon,
create,
echo,
insert,
copy,
unlock,
lock,
import,
@@ -73,6 +78,10 @@ fn main_err(matches: &ArgMatches) -> Result<()> {
generate,
sync
);
#[cfg(any(feature = "copy", feature = "copy-wayland"))]
{
subcmds.insert("copy".to_string(), cmd::copy::main);
}
let (cmd, subm) = matches.subcommand();
// We are requiring a subcommand.
let subm = subm.unwrap();


+ 1
- 1
src/term.rs View File

@@ -6,7 +6,7 @@ pub use term_crate::Attr;
pub use term_crate::Attr::*;
pub use term_crate::color::*;

pub struct Term<O>(Option<Box<Terminal<Output = O> + Send>>);
pub struct Term<O>(Option<Box<dyn Terminal<Output = O> + Send>>);

pub struct CDisplay<'a, D: 'a + Display + ?Sized>(Attr, &'a D);



+ 14
- 1
src/util.rs View File

@@ -1,8 +1,11 @@
use cfg::Config;
use clap::ArgMatches;
#[cfg(feature = "copy")]
use clipboard::{ClipboardContext, ClipboardProvider};
#[cfg(target_os = "linux")]
#[cfg(all(feature = "copy", target_os = "linux"))]
use clipboard::x11_clipboard::{Primary, X11ClipboardContext};
#[cfg(feature = "copy-wayland")]
use wl_clipboard_rs::copy::{MimeType, Options, Source, ClipboardType, ServeRequests};
use err::{Error, Result};
use goblin_core::{Access, DeltaMetadata, Scope, Status, UnlockSpec};
use goblin_core::ipc::Client;
@@ -55,6 +58,7 @@ pub fn init_timeout() {
});
}

#[cfg(feature = "copy")]
pub fn copy(val: String) -> Result<()> {
#[cfg(target_os = "linux")]
{
@@ -66,6 +70,15 @@ pub fn copy(val: String) -> Result<()> {
Ok(())
}

#[cfg(feature = "copy-wayland")]
pub fn copy(val: String) -> Result<()> {
let mut opts = Options::new();
opts.clipboard(ClipboardType::Both)
.serve_requests(ServeRequests::Only(1))
.foreground(true);
opts.copy(Source::Bytes(val.into_bytes().into()), MimeType::Autodetect)?;
Ok(())
}
pub fn should_autocommit(
cli: &mut Client,
matches: &ArgMatches,


+ 3
- 1
update.sh View File

@@ -1,5 +1,7 @@
#!/bin/sh
cargo update
# run cargo update manually. Take care with hermit-abi -- 0.1.6 is broken on
# stable. Try 0.1.3.
#cargo update
sed -i 's/?branch=[a-z\-]*//g' Cargo.lock
carnix generate-nix --src=./. --standalone
sed -i 's/with import <nixpkgs> {};/{ pkgs }: with pkgs;/g' Cargo.nix

Loading…
Cancel
Save