Merge pull request #929 from matthiasbeyer/fix-build-quick
Remove libimagruby
This commit is contained in:
commit
8eaead5f52
24 changed files with 2 additions and 2059 deletions
18
.travis.yml
18
.travis.yml
|
@ -10,23 +10,9 @@ language: rust
|
|||
matrix:
|
||||
include:
|
||||
- rust: 1.13.0
|
||||
env: IMAG_RUBY_VERSION=2.3.3
|
||||
- rust: 1.13.0
|
||||
env: IMAG_RUBY_VERSION=2.4.0
|
||||
|
||||
cache:
|
||||
cargo: true
|
||||
directories:
|
||||
- $TRAVIS_BUILD_DIR/libimagruby/vendor/bundle
|
||||
|
||||
before_install:
|
||||
- |
|
||||
rvm install "$IMAG_RUBY_VERSION"
|
||||
rvm use "$IMAG_RUBY_VERSION"
|
||||
ruby --version
|
||||
pushd libimagruby
|
||||
bundle install --jobs=3 --retry=3 --path=$TRAVIS_BUILD_DIR/libimagruby/vendor/bundle
|
||||
popd
|
||||
|
||||
before_script:
|
||||
- |
|
||||
|
@ -44,7 +30,6 @@ addons:
|
|||
- libcurl4-openssl-dev
|
||||
- libdw-dev
|
||||
- libelf-dev
|
||||
- libruby
|
||||
- libzzip-dev
|
||||
- make
|
||||
- tree
|
||||
|
@ -71,6 +56,3 @@ env:
|
|||
global:
|
||||
- THERMITE_DEBUG_FILENAME=/tmp/thermite-debug.log
|
||||
- secure: D+3exBnbvzFvk7fvLOxkF7UotCc4gBbvvOW4xGr9u6dDjEjV5y6CdDy/OQAkhfKhvSou+lIC22g5MuCBQXFEf/ua7A1XzwBAFeVLK4cWZSa7+ql6LdHKqOg3oF6pQlh095WeWr8S2PYJFFJFg8RGUPnbjqdu1J4KSXqe/7GoZ3lYS69mx7D5Hb93KEN084/KGfBuvyJtMjO1fK3spltL2zV8oqegFpv0gLG5GY4LsJ/7ij4Mc6wepXSyyQbaiA1eKMMwQZDvoi4V1mCulo/jeC3pucGxvgnMV5DZs8aa8R7votltGvSpHCgU78LW19dg8oZqwShQQ+XUYw27H+QK5V1lz1l1MaJLbwS3ySyZBPGH8qUuOzQ3bLp9xhAIRgCui3kX/UDhmeME7nJI6k3UZydh+/ydNB1BZHTKn76XS/yFj0Gcibxg7f5fcAYA6Ge5Sg+YPozuwbcKnKe6IpN2M7qNgWa+6MCSXJ1v4BgPb7kN74EynJUM8+yWEFN7MZtWEUQ4ZsHdCs8Pub4C/zHpYGV8qGenZwQzosAFq56YwoGCvJezz35yg4BDd3IMKenOzNnXLBrdxxqX8ySgwt5B3zBqwve/64Lx6OXjae2m8wZKlsmeqad/s6K7nx0zG15/qqRIzyvgcLXq3jwBaHkteq49FRFWvHQFpBQcsPZ2uH4=
|
||||
matrix:
|
||||
- IMAG_RUBY_VERSION=2.3.3
|
||||
- IMAG_RUBY_VERSION=2.4.0
|
||||
|
|
|
@ -21,7 +21,6 @@ members = [
|
|||
"libimagnotes",
|
||||
"libimagref",
|
||||
"libimagrt",
|
||||
"libimagruby",
|
||||
"libimagstore",
|
||||
"libimagstorestdhook",
|
||||
"libimagtimeui",
|
||||
|
|
10
Makefile
10
Makefile
|
@ -47,18 +47,12 @@ bin: $(BIN_TARGETS) imag-bin
|
|||
|
||||
bin-test: $(BIN_TARGET_TESTS) imag-bin
|
||||
|
||||
lib: $(LIB_TARGETS) lib-imag-ruby-tarball
|
||||
lib: $(LIB_TARGETS)
|
||||
@$(ECHO) "\t[ALLLIB ]"
|
||||
|
||||
lib-test: $(LIB_TARGETS_TEST)
|
||||
|
||||
lib-imag-ruby-tarball:
|
||||
@$(MAKE) -C libimagruby tarball
|
||||
|
||||
lib-imag-ruby-test:
|
||||
@$(MAKE) -C libimagruby test
|
||||
|
||||
test: bin-test lib-test lib-imag-ruby-test
|
||||
test: bin-test lib-test
|
||||
|
||||
install: $(INSTALL_TARGETS) imag-bin-install
|
||||
@$(ECHO) "\t[INSTALL]"
|
||||
|
|
|
@ -7,7 +7,6 @@ let
|
|||
];
|
||||
|
||||
dependencies = with pkgs; [
|
||||
ruby
|
||||
bundler
|
||||
cmake
|
||||
curl
|
||||
|
|
5
libimagruby/.gitignore
vendored
5
libimagruby/.gitignore
vendored
|
@ -1,5 +0,0 @@
|
|||
.bundle
|
||||
Gemfile.lock
|
||||
lib/liblibimagruby.so
|
||||
vendor/bundle
|
||||
libimagruby*.tar.gz
|
|
@ -1,41 +0,0 @@
|
|||
[package]
|
||||
name = "libimagruby"
|
||||
version = "0.1.0"
|
||||
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
||||
|
||||
description = "Library for the imag core distribution"
|
||||
|
||||
keywords = ["imag", "PIM", "personal", "information", "management"]
|
||||
readme = "../README.md"
|
||||
license = "LGPL-2.1"
|
||||
|
||||
documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html"
|
||||
repository = "https://github.com/matthiasbeyer/imag"
|
||||
homepage = "http://imag-pim.org"
|
||||
|
||||
[lib]
|
||||
crate-type = ["dylib"]
|
||||
|
||||
[dependencies]
|
||||
ruru = "0.9"
|
||||
lazy_static = "0.2"
|
||||
log = "0.3"
|
||||
env_logger = "0.3"
|
||||
toml = "0.2"
|
||||
uuid = { version = "0.3", features = ["v4"] }
|
||||
|
||||
[dependencies.libimagerror]
|
||||
path = "../libimagerror"
|
||||
|
||||
[dependencies.libimagrt]
|
||||
path = "../libimagrt"
|
||||
|
||||
[dependencies.libimagstore]
|
||||
path = "../libimagstore"
|
||||
|
||||
[dependencies.libimagstorestdhook]
|
||||
path = "../libimagstorestdhook"
|
||||
|
||||
[dependencies.libimagutil]
|
||||
path = "../libimagutil"
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
source "https://rubygems.org"
|
||||
|
||||
gemspec
|
|
@ -1,22 +0,0 @@
|
|||
ECHO=$(shell which echo) -e
|
||||
RUBY=$(shell which ruby)
|
||||
BUNDLE=$(shell which bundle)
|
||||
|
||||
all:
|
||||
@$(ECHO) "There is no default target here"
|
||||
|
||||
bundle:
|
||||
@$(ECHO) "[BUNDLE]"
|
||||
@$(BUNDLE) install --path vendor/bundle
|
||||
|
||||
tarball: bundle
|
||||
@$(ECHO) "[RAKE ][thermite]"
|
||||
@CARGO_TARGET=debug $(BUNDLE) exec rake thermite:tarball
|
||||
|
||||
test: tarball
|
||||
@$(ECHO) "[TEST ] Not yet implemented. :-("
|
||||
|
||||
.FORCE:
|
||||
|
||||
.PHONY: all
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
# imag-ruby
|
||||
|
||||
A Ruby gem for scripting imag modules.
|
||||
|
||||
## How does this work?
|
||||
|
||||
Well, as we have some problems with lifetimes here, we have a fairly complex
|
||||
codebase in this crate.
|
||||
|
||||
### The Problem
|
||||
|
||||
The Problem is, that `libimagstore::store::FileLockEntry<'a>` has a lifetime. If
|
||||
we would wrap this object into a ruru wrapper and pass to the Ruby code, we
|
||||
couldn't guarantee anymore that the lifetime holds.
|
||||
|
||||
The problem is simple, you see...
|
||||
|
||||
### The solution?
|
||||
|
||||
Never pass anything to the Ruby code.
|
||||
|
||||
Yes, exactly. The Ruby code only sees 'handles'. It never actually gets the
|
||||
`Store` object either.
|
||||
We move the `Store` Object into a `Cache` object (actually, the Ruby code could
|
||||
have multiple `Store` objects to work with this way) and return a `StoreHandle`
|
||||
to the Ruby code (which is a UUID underneath).
|
||||
|
||||
Also, the Ruby code never actually touches a `FileLockEntry` - it only gets a
|
||||
Handle for each `FileLockEntry` - which is a tuple of the `StoreHandle` and the
|
||||
`libimagstore::storeid::StoreId` for the Entry.
|
||||
|
||||
Each operation on a `FileLockEntry` is then wrapped by this very library. Each
|
||||
time `FileLockEntry` is touched, this library fetches the appropriate `Store`
|
||||
object from the static `Cache`, then fetches the `FileLockEntry` object from it,
|
||||
does the operation and then drops the object (which implies that the actual
|
||||
`FileLockEntry` is `update()`d!).
|
||||
|
||||
### The Hell?
|
||||
|
||||
Yes, I know this is a lot of overhead. But what are we talking about here? This
|
||||
is Ruby code we're talking about here, so speed is not our concern.
|
||||
|
||||
You could argue this is a hell of complexity introduced in this library and yes
|
||||
it is.
|
||||
If there are bugs (and I bet there are) they would be complex as hell.
|
||||
But that's it... if you have a better approach, please file a PR.
|
||||
|
||||
## Tests?
|
||||
|
||||
We have tests Ruby scripts in `./test`, they are not executed by travis-ci, as
|
||||
we need Ruby `2.3.0` for this and travis has `2.2.0` as latest version.
|
||||
But I hope we get it in travis soonish.
|
||||
|
||||
## Ruby gem?
|
||||
|
||||
This crate will contain both the Rust bindings for imag using `ruru` and a bunch
|
||||
of wrapper code for the actual `imag` gem.
|
||||
|
||||
### Why another layer of indirection?
|
||||
|
||||
As "ruru" does not yet support modules (which is sad btw) we would end up with
|
||||
functions for all the things.
|
||||
|
||||
E.G.: `imag_runtime_setup()` instead of `Imag::Runtime::setup()`
|
||||
|
||||
I want to add a Ruby gem to wrap these things.
|
||||
|
||||
So basically a piece of Ruby which uses the Rust code to build
|
||||
`imag` as a gem which then exports a fine module system.
|
||||
|
||||
### The module system:
|
||||
|
||||
```text
|
||||
Imag (Module)
|
||||
EntryContent (Class (inherits from String))
|
||||
EntryHeader (Class)
|
||||
FileLockEntryHandle (Class)
|
||||
StoreHandle (Class)
|
||||
StoreId (Class)
|
||||
```
|
||||
|
||||
`libimagentrytag` and the other `libimagentry*` libraries will be pulled into
|
||||
this library to support more advanced operations with the `FileLockEntryHandle`
|
||||
type.
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
require "bundler/gem_tasks"
|
||||
require 'thermite/tasks'
|
||||
|
||||
Thermite::Tasks.new(cargo_project_path: "..", cargo_workspace_member: "libimagruby")
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
require 'thermite/tasks'
|
||||
|
||||
Thermite::Tasks.new(cargo_project_path: "..", cargo_workspace_member: "libimagruby")
|
||||
task default: %w(thermite:build)
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
# coding: utf-8
|
||||
lib = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'imag/version'
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "imag"
|
||||
spec.version = Imag::VERSION
|
||||
spec.authors = ["Matthias Beyer"]
|
||||
spec.email = ["mail@beyermatthias.de"]
|
||||
|
||||
spec.summary = %q{A Ruby gem to script imag.}
|
||||
spec.description = %q{A Ruby gem to script imag, the personal information management suite for the commandline}
|
||||
spec.homepage = "http://imag-pim.org"
|
||||
|
||||
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
||||
f.match(%r{^(test|spec|features)/})
|
||||
end
|
||||
|
||||
spec.bindir = "exe"
|
||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.add_development_dependency "bundler", "~> 1.13"
|
||||
spec.add_development_dependency "rake", "~> 10.0"
|
||||
spec.add_development_dependency 'thermite', "~> 0.11", ">= 0.11.1"
|
||||
|
||||
spec.extensions << 'ext/Rakefile'
|
||||
end
|
|
@ -1,140 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
# imag ruby interface module
|
||||
#
|
||||
# This module is created because the library which is used to write the Ruby
|
||||
# bindings in Rust does not support modules.
|
||||
#
|
||||
# This is a wrapper to have nice Ruby-like things in the Ruby codebase and for
|
||||
# beeing backwards compatible as soon as the Rust library gets module support.
|
||||
#
|
||||
# There will probably always be a wrapper for the Rust library, to be more
|
||||
# flexible with the API, though.
|
||||
module Imag
|
||||
|
||||
# Function name of the function to call to initialize the Rust backend part.
|
||||
# Do not use.
|
||||
IMAG_INIT_FN_NAME = 'imag_ruby_initialize'
|
||||
|
||||
# Setup method
|
||||
#
|
||||
# Call this method for initializing the library.
|
||||
# It dynamically creates the classes for the imag library.
|
||||
def self.setup binary_path
|
||||
require binary_path
|
||||
|
||||
self.core_setup
|
||||
self.classes_setup
|
||||
end
|
||||
|
||||
# Abstraction over the logger frontend of the binary
|
||||
#
|
||||
# This is just a translation to nice Ruby code
|
||||
module Logger
|
||||
|
||||
def self.init cfg
|
||||
debug = !!cfg[:debug]
|
||||
verbose = !!cfg[:verbose]
|
||||
color = !!cfg[:color]
|
||||
::RImag.init_logger debug, verbose, color
|
||||
end
|
||||
|
||||
# Log text with "trace" level in imag
|
||||
def self.trace msg
|
||||
::RImag.trace msg
|
||||
end
|
||||
|
||||
# Log text with "debug" level in imag
|
||||
def self.dbg msg
|
||||
::RImag.dbg msg
|
||||
end
|
||||
|
||||
# Log text with "debug" level in imag (alias for Imag::Logger::dbg)
|
||||
def self.debug msg
|
||||
::RImag.debug msg
|
||||
end
|
||||
|
||||
# Log text with "info" level in imag
|
||||
def self.info msg
|
||||
::RImag.info msg
|
||||
end
|
||||
|
||||
# Log text with "warning" level in imag
|
||||
def self.warn msg
|
||||
::RImag.warn msg
|
||||
end
|
||||
|
||||
# Log text with "error" level in imag
|
||||
def self.error msg
|
||||
::RImag.error msg
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Class names of the Classes in the Ruby scope
|
||||
#
|
||||
# These classes are created by the Rust backend with an "R" prefix, and are
|
||||
# here mapped to Ruby classes by inheriting from them.
|
||||
#
|
||||
# Addidional functionality and convenience methods can then be set up upon
|
||||
# these pure Ruby classes.
|
||||
def self.class_names
|
||||
[
|
||||
:StoreId ,
|
||||
:StoreHandle ,
|
||||
:FileLockEntryHandle ,
|
||||
:EntryHeader ,
|
||||
:EntryContent ,
|
||||
]
|
||||
end
|
||||
|
||||
# Do the core setup
|
||||
#
|
||||
# Maps the Rust classes to Ruby classes by inheriting from them
|
||||
def self.core_setup
|
||||
self.class_names.map {|n| [n, "R#{n}".to_sym ] }.each do |elem|
|
||||
Imag.const_set elem.first, Kernel.const_get(elem.last)
|
||||
end
|
||||
end
|
||||
|
||||
# Class setup
|
||||
#
|
||||
# Summarizing method for calling all the class-setup methods.
|
||||
def self.classes_setup
|
||||
self.class_storeid_setup
|
||||
end
|
||||
|
||||
# Class setup for the StoreId class
|
||||
#
|
||||
# Sets up additional methods for the Imag::StoreId class.
|
||||
def self.class_storeid_setup
|
||||
Imag::StoreId.class_exec do
|
||||
def to_s
|
||||
self.to_str
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if __FILE__ == $0
|
||||
puts "Running some tests..."
|
||||
puts "I hope you passed the library object as first argument..."
|
||||
begin
|
||||
Imag.setup ARGV.first
|
||||
rescue Exception => e
|
||||
puts "Seems not to be the case... or something else went wrong..."
|
||||
puts e
|
||||
exit 1
|
||||
end
|
||||
|
||||
Imag::Logger.init debug: true, verbose: true, color: true
|
||||
Imag::Logger.info "The Logger should work now"
|
||||
|
||||
Imag::Logger.info "Lets see whether we have properly setup StoreId"
|
||||
Imag::Logger.info Imag::StoreId::new_baseless("baselessId").to_s
|
||||
Imag::Logger.info "Seems good."
|
||||
end
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
module Imag
|
||||
VERSION = "0.1.0"
|
||||
end
|
|
@ -1,42 +0,0 @@
|
|||
//
|
||||
// imag - the personal information management suite for the commandline
|
||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; version
|
||||
// 2.1 of the License.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use uuid::Uuid;
|
||||
|
||||
use libimagstore::store::Store;
|
||||
|
||||
#[derive(Clone, Debug, Ord, Hash, Eq, PartialOrd, PartialEq)]
|
||||
pub struct StoreHandle(Uuid);
|
||||
|
||||
impl StoreHandle {
|
||||
pub fn new() -> StoreHandle {
|
||||
StoreHandle(Uuid::new_v4())
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref RUBY_STORE_CACHE: Arc<Mutex<BTreeMap<StoreHandle, Store>>> = {
|
||||
Arc::new(Mutex::new(BTreeMap::new()))
|
||||
};
|
||||
}
|
||||
|
|
@ -1,276 +0,0 @@
|
|||
//
|
||||
// imag - the personal information management suite for the commandline
|
||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; version
|
||||
// 2.1 of the License.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
#[allow(unused_variables)]
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
use ruru::{Class, Object, AnyObject, Boolean, RString, VM, Hash, NilClass, VerifiedObject};
|
||||
use toml::Value;
|
||||
|
||||
use libimagstore::store::EntryContent;
|
||||
use libimagstore::store::Entry;
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagstore::toml_ext::TomlValueExt;
|
||||
|
||||
use ruby_utils::IntoToml;
|
||||
use toml_utils::IntoRuby;
|
||||
use util::Wrap;
|
||||
use util::Unwrap;
|
||||
use cache::StoreHandle;
|
||||
|
||||
pub struct FileLockEntryHandle(StoreHandle, StoreId);
|
||||
|
||||
impl FileLockEntryHandle {
|
||||
pub fn new(sh: StoreHandle, id: StoreId) -> FileLockEntryHandle {
|
||||
FileLockEntryHandle(sh, id)
|
||||
}
|
||||
|
||||
pub fn store_handle(&self) -> &StoreHandle {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn fle_handle(&self) -> &StoreId {
|
||||
&self.1
|
||||
}
|
||||
}
|
||||
|
||||
wrappable_struct!(FileLockEntryHandle, FileLockEntryWrapper, FLE_WRAPPER);
|
||||
class!(RFileLockEntryHandle);
|
||||
impl_wrap!(FileLockEntryHandle => FLE_WRAPPER);
|
||||
impl_unwrap!(RFileLockEntryHandle => FileLockEntryHandle => FLE_WRAPPER);
|
||||
impl_verified_object!(RFileLockEntryHandle);
|
||||
|
||||
/// Helper macro for operating on RUBY_STORE_CACHE object
|
||||
///
|
||||
/// This helps us calling operations on FileLockEntry objects.
|
||||
///
|
||||
/// What I do here: Fetch the Store object from the cache, fetch the appropriate FileLockEntry and
|
||||
/// call the operation on it.
|
||||
///
|
||||
/// This could be improved with another cache, so not the store is cached but the FileLockEntry
|
||||
/// only, but then we run into lifetime problems with the Store and its FileLockEntry objects.
|
||||
/// Feel free to fix this, but for now, this is a workable solution.
|
||||
///
|
||||
#[macro_export]
|
||||
macro_rules! call_on_fle_from_store {
|
||||
($itself:ident ($wrapper:ident) -> $name:ident -> $operation:block) => {{
|
||||
let handle = $itself.get_data(&*$wrapper);
|
||||
let store_handle = handle.store_handle();
|
||||
call_on_store_by_handle! {
|
||||
store_handle named store inside {
|
||||
match store.get(handle.fle_handle().clone()) {
|
||||
Ok(Some(mut $name)) => {
|
||||
$operation
|
||||
},
|
||||
Ok(None) => {
|
||||
VM::raise(Class::from_existing("RImagStoreReadError"), "Obj does not exist");
|
||||
NilClass::new().to_any_object()
|
||||
},
|
||||
Err(e) => {
|
||||
VM::raise(Class::from_existing("RImagStoreReadError"), e.description());
|
||||
NilClass::new().to_any_object()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}};
|
||||
($itself:ident ($wrapper:ident) -> $name:ident -> $operation: block on fail return $ex:expr) => {{
|
||||
let handle = $itself.get_data(&*$wrapper);
|
||||
let store_handle = handle.store_handle();
|
||||
call_on_store_by_handle! {
|
||||
store_handle named store inside {
|
||||
match store.get(handle.fle_handle().clone()) {
|
||||
Ok(Some(mut $name)) => {
|
||||
$operation
|
||||
},
|
||||
Ok(None) => {
|
||||
VM::raise(Class::from_existing("RImagStoreReadError"), "Obj does not exist");
|
||||
$ex
|
||||
},
|
||||
Err(e) => {
|
||||
VM::raise(Class::from_existing("RImagStoreReadError"), e.description());
|
||||
$ex
|
||||
},
|
||||
}
|
||||
} on fail return $ex
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
methods!(
|
||||
RFileLockEntryHandle,
|
||||
itself,
|
||||
|
||||
fn r_get_location() -> AnyObject {
|
||||
call_on_fle_from_store!(itself (FLE_WRAPPER) -> fle -> { fle.get_location().clone().wrap() })
|
||||
}
|
||||
|
||||
fn r_get_header() -> AnyObject {
|
||||
call_on_fle_from_store!(itself (FLE_WRAPPER) -> fle -> { fle.get_header().clone().wrap() })
|
||||
}
|
||||
|
||||
fn r_set_header(hdr: Hash) -> NilClass {
|
||||
use ruby_utils::IntoToml;
|
||||
use toml::Value;
|
||||
|
||||
let entryheader = match typecheck!(hdr or return NilClass::new()).into_toml() {
|
||||
Value::Table(t) => Value::Table(t),
|
||||
_ => {
|
||||
let ec = Class::from_existing("RImagEntryHeaderWriteError");
|
||||
VM::raise(ec, "Something weird happened. Hash seems to be not a Hash");
|
||||
return NilClass::new();
|
||||
},
|
||||
};
|
||||
|
||||
call_on_fle_from_store!(itself (FLE_WRAPPER) -> fle -> {
|
||||
*fle.get_header_mut() = entryheader;
|
||||
NilClass::new().to_any_object()
|
||||
});
|
||||
|
||||
NilClass::new()
|
||||
}
|
||||
|
||||
fn r_get_content() -> AnyObject {
|
||||
call_on_fle_from_store!(itself (FLE_WRAPPER) -> fle -> {
|
||||
fle.get_content().clone().wrap()
|
||||
} on fail return NilClass::new().to_any_object())
|
||||
}
|
||||
|
||||
fn r_set_content(ctt: RString) -> NilClass {
|
||||
use ruby_utils::IntoToml;
|
||||
use toml::Value;
|
||||
|
||||
let content = match typecheck!(ctt).into_toml() {
|
||||
Value::String(s) => s,
|
||||
_ => {
|
||||
let ec = Class::from_existing("RImagEntryError");
|
||||
VM::raise(ec, "Something weird happened. String seems to be not a String");
|
||||
return NilClass::new();
|
||||
},
|
||||
};
|
||||
|
||||
call_on_fle_from_store!(itself (FLE_WRAPPER) -> fle -> {
|
||||
*fle.get_content_mut() = content;
|
||||
NilClass::new().to_any_object()
|
||||
});
|
||||
|
||||
NilClass::new()
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
wrappable_struct!(Value, EntryHeaderWrapper, ENTRY_HEADER_WRAPPER);
|
||||
class!(REntryHeader);
|
||||
impl_wrap!(Value => ENTRY_HEADER_WRAPPER);
|
||||
impl_unwrap!(REntryHeader => Value => ENTRY_HEADER_WRAPPER);
|
||||
impl_verified_object!(REntryHeader);
|
||||
|
||||
methods!(
|
||||
REntryHeader,
|
||||
itself,
|
||||
|
||||
fn r_entry_header_new() -> AnyObject {
|
||||
Entry::default_header().wrap()
|
||||
}
|
||||
|
||||
fn r_entry_header_insert(spec: RString, obj: AnyObject) -> Boolean {
|
||||
let spec = typecheck!(spec or return Boolean::new(false)).to_string();
|
||||
let obj = obj.unwrap(); // possibly not safe... TODO
|
||||
|
||||
match itself.get_data(&*ENTRY_HEADER_WRAPPER).insert(&spec, obj.into_toml()) {
|
||||
Ok(b) => Boolean::new(b),
|
||||
Err(e) => {
|
||||
VM::raise(Class::from_existing("RImagEntryHeaderWriteError"), e.description());
|
||||
Boolean::new(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn r_entry_header_set(spec: RString, obj: AnyObject) -> AnyObject {
|
||||
use ruru::NilClass;
|
||||
|
||||
let spec = typecheck!(spec or return any Boolean::new(false)).to_string();
|
||||
let obj = obj.unwrap(); // possibly not safe... TODO
|
||||
|
||||
match itself.get_data(&*ENTRY_HEADER_WRAPPER).set(&spec, obj.into_toml()) {
|
||||
Ok(Some(v)) => v.into_ruby(),
|
||||
Ok(None) => NilClass::new().to_any_object(),
|
||||
Err(e) => {
|
||||
VM::raise(Class::from_existing("RImagEntryHeaderWriteError"), e.description());
|
||||
return Boolean::new(false).to_any_object();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn r_entry_header_get(spec: RString) -> AnyObject {
|
||||
use ruru::NilClass;
|
||||
|
||||
let spec = typecheck!(spec or return any Boolean::new(false)).to_string();
|
||||
|
||||
match itself.get_data(&*ENTRY_HEADER_WRAPPER).read(&spec) {
|
||||
Ok(Some(v)) => v.into_ruby(),
|
||||
Ok(None) => NilClass::new().to_any_object(),
|
||||
Err(e) => {
|
||||
VM::raise(Class::from_existing("RImagEntryHeaderReadError"), e.description());
|
||||
return Boolean::new(false).to_any_object();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
wrappable_struct!(EntryContent, EntryContentWrapper, ENTRY_CONTENT_WRAPPER);
|
||||
class!(REntryContent);
|
||||
impl_wrap!(EntryContent => ENTRY_CONTENT_WRAPPER);
|
||||
impl_unwrap!(REntryContent => EntryContent => ENTRY_CONTENT_WRAPPER);
|
||||
|
||||
wrappable_struct!(Entry, EntryWrapper, ENTRY_WRAPPER);
|
||||
class!(REntry);
|
||||
impl_unwrap!(REntry => Entry => ENTRY_WRAPPER);
|
||||
|
||||
pub fn setup_filelockentry() -> Class {
|
||||
let mut class = Class::new("RFileLockEntryHandle", None);
|
||||
class.define(|itself| {
|
||||
itself.def("location", r_get_location);
|
||||
itself.def("header" , r_get_header);
|
||||
itself.def("header=" , r_set_header);
|
||||
itself.def("content" , r_get_content);
|
||||
itself.def("content=", r_set_content);
|
||||
});
|
||||
class
|
||||
}
|
||||
|
||||
pub fn setup_entryheader() -> Class {
|
||||
let mut class = Class::new("REntryHeader", None);
|
||||
class.define(|itself| {
|
||||
itself.def("insert", r_entry_header_insert);
|
||||
itself.def("set" , r_entry_header_set);
|
||||
itself.def("[]=" , r_entry_header_set);
|
||||
itself.def("read" , r_entry_header_get);
|
||||
itself.def("[]" , r_entry_header_get);
|
||||
});
|
||||
class
|
||||
}
|
||||
|
||||
pub fn setup_entrycontent() -> Class {
|
||||
let string = Class::from_existing("String");
|
||||
Class::new("REntryContent", Some(&string))
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
//
|
||||
// imag - the personal information management suite for the commandline
|
||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; version
|
||||
// 2.1 of the License.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use ruru::Class;
|
||||
|
||||
class!(RImagError);
|
||||
class!(RImagObjDoesNotExistError);
|
||||
class!(RImagStoreError);
|
||||
class!(RImagStoreWriteError);
|
||||
class!(RImagStoreReadError);
|
||||
class!(RImagEntryError);
|
||||
class!(RImagEntryHeaderError);
|
||||
class!(RImagEntryHeaderReadError);
|
||||
class!(RImagEntryHeaderWriteError);
|
||||
class!(RImagTypeError);
|
||||
|
||||
pub fn setup() {
|
||||
let imag_error = Class::new("RImagError", Some(&Class::from_existing("RuntimeError")));
|
||||
Class::new("RImagObjDoesNotExistError" , Some(&imag_error));
|
||||
|
||||
{
|
||||
let imag_store_error = Class::new("RImagStoreError", Some(&imag_error));
|
||||
Class::new("RImagStoreWriteError", Some(&imag_store_error));
|
||||
Class::new("RImagStoreReadError" , Some(&imag_store_error));
|
||||
}
|
||||
|
||||
{
|
||||
let imag_entry_error = Class::new("RImagEntryError" , Some(&imag_error));
|
||||
let imag_entry_header_error = Class::new("RImagEntryHeaderError", Some(&imag_entry_error));
|
||||
Class::new("RImagEntryHeaderReadError" , Some(&imag_entry_header_error));
|
||||
Class::new("RImagEntryHeaderWriteError", Some(&imag_entry_header_error));
|
||||
}
|
||||
|
||||
Class::new("RImagTypeError", Some(&imag_error));
|
||||
}
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
//
|
||||
// imag - the personal information management suite for the commandline
|
||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; version
|
||||
// 2.1 of the License.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
#[allow(unused_variables)]
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
use ruru::{Class, Boolean, RString, NilClass, VM, Object};
|
||||
|
||||
use libimagrt::logger::ImagLogger;
|
||||
|
||||
class!(RImag);
|
||||
|
||||
methods!(
|
||||
RImag,
|
||||
itself,
|
||||
|
||||
fn r_initialize_logger(debug: Boolean, verbose: Boolean, colored: Boolean) -> NilClass {
|
||||
use std::env::var as env_var;
|
||||
use env_logger;
|
||||
use log;
|
||||
use log::LogLevelFilter;
|
||||
|
||||
let debug = match debug {
|
||||
Ok(d) => d.to_bool(),
|
||||
Err(ref e) => {
|
||||
VM::raise(e.to_exception(), e.description());
|
||||
return NilClass::new();
|
||||
},
|
||||
};
|
||||
|
||||
let verbose = match verbose {
|
||||
Ok(v) => v.to_bool(),
|
||||
Err(ref e) => {
|
||||
VM::raise(e.to_exception(), e.description());
|
||||
return NilClass::new();
|
||||
},
|
||||
};
|
||||
|
||||
let colored = match colored {
|
||||
Ok(c) => c.to_bool(),
|
||||
Err(ref e) => {
|
||||
VM::raise(e.to_exception(), e.description());
|
||||
return NilClass::new();
|
||||
},
|
||||
};
|
||||
|
||||
if env_var("IMAG_LOG_ENV").is_ok() {
|
||||
env_logger::init().unwrap();
|
||||
} else {
|
||||
let lvl = if debug {
|
||||
LogLevelFilter::Debug
|
||||
} else if verbose {
|
||||
LogLevelFilter::Info
|
||||
} else {
|
||||
LogLevelFilter::Warn
|
||||
};
|
||||
|
||||
log::set_logger(|max_log_lvl| {
|
||||
max_log_lvl.set(lvl);
|
||||
debug!("Init logger with {}", lvl);
|
||||
let lgr = ImagLogger::new(lvl.to_log_level().unwrap())
|
||||
.with_color(colored)
|
||||
.with_prefix("[imag][ruby]".to_owned())
|
||||
.with_dbg_file_and_line(false);
|
||||
Box::new(lgr)
|
||||
})
|
||||
.map_err(|_| {
|
||||
panic!("Could not setup logger");
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
||||
NilClass::new()
|
||||
}
|
||||
|
||||
fn r_log_trace(l: RString) -> NilClass {
|
||||
match l {
|
||||
Err(ref e) => VM::raise(e.to_exception(), e.description()),
|
||||
Ok(s) => trace!("{}", s.to_string()),
|
||||
}
|
||||
NilClass::new()
|
||||
}
|
||||
|
||||
fn r_log_debug(l: RString) -> NilClass {
|
||||
match l {
|
||||
Err(ref e) => VM::raise(e.to_exception(), e.description()),
|
||||
Ok(s) => debug!("{}", s.to_string()),
|
||||
}
|
||||
NilClass::new()
|
||||
}
|
||||
|
||||
fn r_log_info(l: RString) -> NilClass {
|
||||
match l {
|
||||
Err(ref e) => VM::raise(e.to_exception(), e.description()),
|
||||
Ok(s) => info!("{}", s.to_string()),
|
||||
}
|
||||
NilClass::new()
|
||||
}
|
||||
|
||||
fn r_log_warn(l: RString) -> NilClass {
|
||||
match l {
|
||||
Err(ref e) => VM::raise(e.to_exception(), e.description()),
|
||||
Ok(s) => warn!("{}", s.to_string()),
|
||||
}
|
||||
NilClass::new()
|
||||
}
|
||||
|
||||
fn r_log_error(l: RString) -> NilClass {
|
||||
match l {
|
||||
Err(ref e) => VM::raise(e.to_exception(), e.description()),
|
||||
Ok(s) => error!("{}", s.to_string()),
|
||||
}
|
||||
NilClass::new()
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
pub fn setup() -> Class {
|
||||
let mut class = Class::new("RImag", None);
|
||||
class.define(|itself| {
|
||||
itself.def_self("init_logger", r_initialize_logger);
|
||||
itself.def_self("trace", r_log_trace);
|
||||
itself.def_self("dbg", r_log_debug);
|
||||
itself.def_self("debug", r_log_debug);
|
||||
itself.def_self("info", r_log_info);
|
||||
itself.def_self("warn", r_log_warn);
|
||||
itself.def_self("error", r_log_error);
|
||||
});
|
||||
class
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
//
|
||||
// imag - the personal information management suite for the commandline
|
||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; version
|
||||
// 2.1 of the License.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
#[macro_use] extern crate ruru;
|
||||
#[macro_use] extern crate lazy_static;
|
||||
#[macro_use] extern crate log;
|
||||
extern crate env_logger;
|
||||
extern crate toml;
|
||||
extern crate uuid;
|
||||
|
||||
#[macro_use] extern crate libimagerror;
|
||||
extern crate libimagstore;
|
||||
extern crate libimagstorestdhook;
|
||||
extern crate libimagrt;
|
||||
#[macro_use] extern crate libimagutil;
|
||||
|
||||
#[macro_use] mod util;
|
||||
#[macro_use] pub mod store;
|
||||
mod cache;
|
||||
|
||||
pub mod error;
|
||||
pub mod entry;
|
||||
pub mod imag;
|
||||
pub mod ruby_utils;
|
||||
pub mod storeid;
|
||||
pub mod toml_utils;
|
||||
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
pub extern fn Init_liblibimagruby() {
|
||||
self::error::setup();
|
||||
self::store::setup();
|
||||
self::storeid::setup();
|
||||
self::entry::setup_filelockentry();
|
||||
self::entry::setup_entryheader();
|
||||
self::entry::setup_entrycontent();
|
||||
self::imag::setup();
|
||||
}
|
||||
|
|
@ -1,210 +0,0 @@
|
|||
//
|
||||
// imag - the personal information management suite for the commandline
|
||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; version
|
||||
// 2.1 of the License.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
// Ruby -> Toml translation primitives
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use ruru::{Object, AnyObject, Class, RString, Fixnum, Float, Symbol, Hash, Array, VM};
|
||||
use ruru::types::ValueType;
|
||||
use toml::Value;
|
||||
|
||||
|
||||
pub trait AsToml : Sized {
|
||||
fn as_toml(&self) -> Value;
|
||||
}
|
||||
|
||||
pub trait IntoToml : AsToml {
|
||||
fn into_toml(self) -> Value {
|
||||
self.as_toml()
|
||||
}
|
||||
}
|
||||
impl<T: AsToml> IntoToml for T { }
|
||||
|
||||
impl AsToml for AnyObject {
|
||||
|
||||
fn as_toml(&self) -> Value {
|
||||
match self.value().ty() {
|
||||
ValueType::None => {
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::Object => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::Class => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::Module => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::Float => self.try_convert_to::<Float>().unwrap().as_toml(),
|
||||
ValueType::RString => self.try_convert_to::<RString>().unwrap().as_toml(),
|
||||
ValueType::Regexp => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::Array => self.try_convert_to::<Array>().unwrap().as_toml(),
|
||||
ValueType::Hash => self.try_convert_to::<Hash>().unwrap().as_toml(),
|
||||
ValueType::Struct => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::Bignum => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::File => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::Data => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::Match => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::Complex => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::Rational => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::Nil => Value::Boolean(false),
|
||||
ValueType::True => Value::Boolean(true),
|
||||
ValueType::False => Value::Boolean(false),
|
||||
ValueType::Symbol => self.try_convert_to::<Symbol>().unwrap().as_toml(),
|
||||
ValueType::Fixnum => self.try_convert_to::<Fixnum>().unwrap().as_toml(),
|
||||
ValueType::Undef => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::Node => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::IClass => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::Zombie => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
ValueType::Mask => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Cannot translate type '' to fit into TOML");
|
||||
Value::Boolean(false)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl AsToml for Hash {
|
||||
|
||||
fn as_toml(&self) -> Value {
|
||||
let mut btm = BTreeMap::new();
|
||||
self.try_convert_to::<Hash>()
|
||||
.unwrap()
|
||||
.each(|key, value| {
|
||||
let key = match key.as_toml() {
|
||||
Value::String(s) => s,
|
||||
_ => {
|
||||
let rte = Class::from_existing("TypeError");
|
||||
VM::raise(rte, "Can only have String or Symbol as Key for TOML maps");
|
||||
String::new()
|
||||
}
|
||||
};
|
||||
let value = value.as_toml();
|
||||
btm.insert(key, value);
|
||||
});
|
||||
Value::Table(btm)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl AsToml for Array {
|
||||
|
||||
fn as_toml(&self) -> Value {
|
||||
let vals = self
|
||||
.try_convert_to::<Array>()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.map(|v| v.as_toml())
|
||||
.collect::<Vec<Value>>();
|
||||
|
||||
Value::Array(vals)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl AsToml for RString {
|
||||
|
||||
fn as_toml(&self) -> Value {
|
||||
Value::String(self.try_convert_to::<RString>().unwrap().to_string())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl AsToml for Float {
|
||||
|
||||
fn as_toml(&self) -> Value {
|
||||
Value::Float(self.try_convert_to::<Float>().unwrap().to_f64())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl AsToml for Symbol {
|
||||
|
||||
fn as_toml(&self) -> Value {
|
||||
Value::String(self.try_convert_to::<Symbol>().unwrap().to_string())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl AsToml for Fixnum {
|
||||
|
||||
fn as_toml(&self) -> Value {
|
||||
Value::Integer(self.try_convert_to::<Fixnum>().unwrap().to_i64())
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,578 +0,0 @@
|
|||
//
|
||||
// imag - the personal information management suite for the commandline
|
||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; version
|
||||
// 2.1 of the License.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
#[allow(unused_variables)]
|
||||
|
||||
use libimagstore::store::Store;
|
||||
use libimagerror::trace::trace_error;
|
||||
use std::error::Error;
|
||||
|
||||
use ruru::{Class, Object, AnyObject, Boolean, RString, VM, NilClass, VerifiedObject};
|
||||
|
||||
use util::Wrap;
|
||||
use util::Unwrap;
|
||||
|
||||
use storeid::RStoreId;
|
||||
use entry::RFileLockEntryHandle;
|
||||
use cache::StoreHandle;
|
||||
|
||||
wrappable_struct!(StoreHandle, StoreWrapper, STORE_WRAPPER);
|
||||
class!(RStoreHandle);
|
||||
impl_wrap!(StoreHandle => STORE_WRAPPER);
|
||||
impl_unwrap!(RStoreHandle => StoreHandle => STORE_WRAPPER);
|
||||
impl_verified_object!(RStoreHandle);
|
||||
|
||||
macro_rules! call_on_store_by_handle {
|
||||
{
|
||||
$store_handle:ident named $name:ident inside $operation:block
|
||||
}=> {{
|
||||
call_on_store_by_handle! {
|
||||
$store_handle
|
||||
named $name
|
||||
inside $operation
|
||||
on fail return NilClass::new().to_any_object()
|
||||
}
|
||||
}};
|
||||
|
||||
{
|
||||
$store_handle:ident named $name:ident inside $operation:block on fail return $ex:expr
|
||||
} => {{
|
||||
use cache::RUBY_STORE_CACHE;
|
||||
|
||||
let arc = RUBY_STORE_CACHE.clone();
|
||||
{
|
||||
let lock = arc.lock();
|
||||
match lock {
|
||||
Ok(mut hm) => {
|
||||
match hm.get($store_handle) {
|
||||
Some($name) => { $operation },
|
||||
None => {
|
||||
VM::raise(Class::from_existing("RImagStoreReadError"),
|
||||
"Tried to operate on non-existing object");
|
||||
$ex
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
VM::raise(Class::from_existing("RImagError"), e.description());
|
||||
$ex
|
||||
}
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! call_on_store {
|
||||
{
|
||||
$store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
|
||||
$fle_name:ident <- fetch $fle_handle_name:ident
|
||||
operation $operation:block
|
||||
} => {
|
||||
call_on_store! {
|
||||
$store_name <- $itself wrapped inside $wrapper,
|
||||
$fle_name <- fetch $fle_handle_name,
|
||||
operation $operation,
|
||||
on fail return NilClass::new()
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
$store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
|
||||
$fle_name:ident <- fetch $fle_handle_name:ident,
|
||||
operation $operation:block,
|
||||
on fail return $fail_expr:expr
|
||||
} => {
|
||||
let handle = $itself.get_data(&*$wrapper);
|
||||
call_on_store_by_handle! {
|
||||
handle named $store_name inside {
|
||||
let $fle_name = match $store_name.get($fle_handle_name) {
|
||||
Ok(Some(fle)) => fle,
|
||||
Ok(None) => {
|
||||
VM::raise(Class::from_existing("RImagStoreReadError"), "Obj does not exist");
|
||||
return $fail_expr
|
||||
},
|
||||
Err(e) => {
|
||||
VM::raise(Class::from_existing("RImagStoreReadError"), e.description());
|
||||
return $fail_expr
|
||||
},
|
||||
};
|
||||
$operation
|
||||
}
|
||||
on fail return $fail_expr
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
$store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
|
||||
operation $operation:block,
|
||||
on fail return $fail_expr:expr
|
||||
} => {
|
||||
let handle = $itself.get_data(&*$wrapper);
|
||||
call_on_store_by_handle! {
|
||||
handle named $store_name inside $operation on fail return $fail_expr
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
$store_name:ident <- $itself:ident wrapped inside $wrapper:ident,
|
||||
operation $block
|
||||
} => {
|
||||
let handle = $itself.get_data(&*$wrapper);
|
||||
call_on_store_by_handle! { handle named $name inside $operation }
|
||||
};
|
||||
}
|
||||
|
||||
methods!(
|
||||
RStoreHandle,
|
||||
itself,
|
||||
|
||||
// Build a new Store object, return a handle to it.
|
||||
//
|
||||
// This function takes a boolean whether the store should include debugging functionality
|
||||
// (namingly the debug hooks) and a runtimepath, where the store lifes.
|
||||
// It then builds a Store object (raising errors on failure and returning Nil) and a handle for
|
||||
// it.
|
||||
// It puts the store object and the handle in the cache and returns the handle as object to the
|
||||
// Ruby code.
|
||||
//
|
||||
// # Returns
|
||||
//
|
||||
// Nil on failure (including raising an error)
|
||||
// StoreHandle on success
|
||||
//
|
||||
fn new(store_debugging: Boolean, rtp: RString) -> AnyObject {
|
||||
use std::path::PathBuf;
|
||||
use libimagerror::trace::trace_error;
|
||||
use libimagerror::trace::trace_error_dbg;
|
||||
use libimagrt::configuration::ConfigErrorKind;
|
||||
use libimagrt::configuration::Configuration;
|
||||
use libimagstore::error::StoreErrorKind;
|
||||
use libimagstore::hook::Hook;
|
||||
use libimagstore::hook::position::HookPosition as HP;
|
||||
use libimagstorestdhook::debug::DebugHook;
|
||||
use libimagstorestdhook::vcs::git::delete::DeleteHook as GitDeleteHook;
|
||||
use libimagstorestdhook::vcs::git::store_unload::StoreUnloadHook as GitStoreUnloadHook;
|
||||
use libimagstorestdhook::vcs::git::update::UpdateHook as GitUpdateHook;
|
||||
|
||||
use cache::RUBY_STORE_CACHE;
|
||||
|
||||
let store_debugging = typecheck!(store_debugging or return any NilClass::new()).to_bool();
|
||||
let rtp = PathBuf::from(typecheck!(rtp or return any NilClass::new()).to_string());
|
||||
|
||||
if !rtp.exists() || !rtp.is_dir() {
|
||||
VM::raise(Class::from_existing("RImagError"), "Runtimepath not a directory");
|
||||
return NilClass::new().to_any_object();
|
||||
}
|
||||
|
||||
let store_config = match Configuration::new(&rtp) {
|
||||
Ok(mut cfg) => cfg.store_config().cloned(),
|
||||
Err(e) => if e.err_type() != ConfigErrorKind::NoConfigFileFound {
|
||||
VM::raise(Class::from_existing("RImagError"), e.description());
|
||||
return NilClass::new().to_any_object();
|
||||
} else {
|
||||
warn!("No config file found.");
|
||||
warn!("Continuing without configuration file");
|
||||
None
|
||||
},
|
||||
};
|
||||
|
||||
let storepath = {
|
||||
let mut spath = rtp.clone();
|
||||
spath.push("store");
|
||||
spath
|
||||
};
|
||||
|
||||
let store = Store::new(storepath.clone(), store_config).map(|mut store| {
|
||||
// If we are debugging, generate hooks for all positions
|
||||
if store_debugging {
|
||||
let hooks : Vec<(Box<Hook>, &str, HP)> = vec![
|
||||
(Box::new(DebugHook::new(HP::PreCreate)) , "debug", HP::PreCreate),
|
||||
(Box::new(DebugHook::new(HP::PostCreate)) , "debug", HP::PostCreate),
|
||||
(Box::new(DebugHook::new(HP::PreRetrieve)) , "debug", HP::PreRetrieve),
|
||||
(Box::new(DebugHook::new(HP::PostRetrieve)) , "debug", HP::PostRetrieve),
|
||||
(Box::new(DebugHook::new(HP::PreUpdate)) , "debug", HP::PreUpdate),
|
||||
(Box::new(DebugHook::new(HP::PostUpdate)) , "debug", HP::PostUpdate),
|
||||
(Box::new(DebugHook::new(HP::PreDelete)) , "debug", HP::PreDelete),
|
||||
(Box::new(DebugHook::new(HP::PostDelete)) , "debug", HP::PostDelete),
|
||||
];
|
||||
|
||||
// If hook registration fails, trace the error and warn, but continue.
|
||||
for (hook, aspectname, position) in hooks {
|
||||
if let Err(e) = store.register_hook(position, &String::from(aspectname), hook) {
|
||||
if e.err_type() == StoreErrorKind::HookRegisterError {
|
||||
trace_error_dbg(&e);
|
||||
warn!("Registering debug hook with store failed");
|
||||
} else {
|
||||
trace_error(&e);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let sp = storepath;
|
||||
|
||||
let hooks : Vec<(Box<Hook>, &str, HP)> = vec![
|
||||
(Box::new(GitDeleteHook::new(sp.clone(), HP::PostDelete)), "vcs", HP::PostDelete),
|
||||
(Box::new(GitUpdateHook::new(sp.clone(), HP::PostUpdate)), "vcs", HP::PostUpdate),
|
||||
(Box::new(GitStoreUnloadHook::new(sp)), "vcs", HP::StoreUnload),
|
||||
];
|
||||
|
||||
for (hook, aspectname, position) in hooks {
|
||||
if let Err(e) = store.register_hook(position, &String::from(aspectname), hook) {
|
||||
if e.err_type() == StoreErrorKind::HookRegisterError {
|
||||
trace_error_dbg(&e);
|
||||
warn!("Registering git hook with store failed");
|
||||
} else {
|
||||
trace_error(&e);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
store
|
||||
});
|
||||
|
||||
let store = match store {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
VM::raise(Class::from_existing("RImagStoreError"), e.description());
|
||||
return NilClass::new().to_any_object();
|
||||
},
|
||||
};
|
||||
|
||||
let store_handle = StoreHandle::new();
|
||||
|
||||
let arc = RUBY_STORE_CACHE.clone();
|
||||
{
|
||||
let lock = arc.lock();
|
||||
match lock {
|
||||
Ok(mut hm) => {
|
||||
hm.insert(store_handle.clone(), store);
|
||||
return store_handle.wrap().to_any_object();
|
||||
},
|
||||
Err(e) => {
|
||||
VM::raise(Class::from_existing("RImagError"), e.description());
|
||||
return NilClass::new().to_any_object();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Create an FileLockEntry in the store
|
||||
//
|
||||
// # Returns:
|
||||
//
|
||||
// On success: A RFileLockEntry
|
||||
// On failure: Nil
|
||||
// On error: Nil + Exception
|
||||
//
|
||||
fn create(id: RStoreId) -> AnyObject {
|
||||
use entry::FileLockEntryHandle;
|
||||
let sid = typecheck!(id or return any NilClass::new()).unwrap().clone();
|
||||
|
||||
call_on_store! {
|
||||
store <- itself wrapped inside STORE_WRAPPER,
|
||||
operation {
|
||||
match store.create(sid.clone()) {
|
||||
Err(e) => {
|
||||
trace_error(&e);
|
||||
VM::raise(Class::from_existing("RImagStoreWriteError"), e.description());
|
||||
NilClass::new().to_any_object()
|
||||
},
|
||||
Ok(entry) => {
|
||||
// Take the location (StoreId) of the entry (we know it exists... so this
|
||||
// is fine) and wrap it into a RFileLockEntry which is then returned to the
|
||||
// user (as handle)
|
||||
let sid = entry.get_location().clone();
|
||||
let store_handle = itself.get_data(&*STORE_WRAPPER).clone();
|
||||
FileLockEntryHandle::new(store_handle, sid).wrap()
|
||||
},
|
||||
}
|
||||
},
|
||||
on fail return NilClass::new().to_any_object()
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve an FileLockEntry from the store
|
||||
//
|
||||
// # Returns:
|
||||
//
|
||||
// On success: A RFileLockEntry
|
||||
// On error: Nil + Exception
|
||||
//
|
||||
fn retrieve(id: RStoreId) -> AnyObject {
|
||||
use entry::FileLockEntryHandle;
|
||||
let sid = typecheck!(id or return any NilClass::new()).unwrap().clone();
|
||||
|
||||
call_on_store! {
|
||||
store <- itself wrapped inside STORE_WRAPPER,
|
||||
operation {
|
||||
match store.retrieve(sid.clone()) {
|
||||
Err(e) => {
|
||||
trace_error(&e);
|
||||
VM::raise(Class::from_existing("RImagStoreWriteError"), e.description());
|
||||
NilClass::new().to_any_object()
|
||||
},
|
||||
Ok(entry) => {
|
||||
// Take the location (StoreId) of the entry (we know it exists... so this
|
||||
// is fine) and wrap it into a RFileLockEntry which is then returned to the
|
||||
// user (as handle)
|
||||
let sid = entry.get_location().clone();
|
||||
let store_handle = itself.get_data(&*STORE_WRAPPER).clone();
|
||||
FileLockEntryHandle::new(store_handle, sid).wrap()
|
||||
},
|
||||
}
|
||||
},
|
||||
on fail return NilClass::new().to_any_object()
|
||||
}
|
||||
}
|
||||
|
||||
// Get an FileLockEntry from the store
|
||||
//
|
||||
// # Returns:
|
||||
//
|
||||
// On success, if there is some: A RFileLockEntry
|
||||
// On success, if there is none: Nil
|
||||
// On error: Nil + Exception
|
||||
//
|
||||
fn get(sid: RStoreId) -> AnyObject {
|
||||
use entry::FileLockEntryHandle;
|
||||
let sid = typecheck!(sid or return any NilClass::new()).unwrap().clone();
|
||||
|
||||
call_on_store! {
|
||||
store <- itself wrapped inside STORE_WRAPPER,
|
||||
operation {
|
||||
match store.get(sid.clone()) {
|
||||
Err(e) => {
|
||||
trace_error(&e);
|
||||
VM::raise(Class::from_existing("RImagStoreWriteError"), e.description());
|
||||
NilClass::new().to_any_object()
|
||||
},
|
||||
Ok(None) => NilClass::new().to_any_object(),
|
||||
Ok(Some(entry)) => {
|
||||
// Take the location (StoreId) of the entry (we know it exists... so this
|
||||
// is fine) and wrap it into a RFileLockEntry which is then returned to the
|
||||
// user (as handle)
|
||||
let sid = entry.get_location().clone();
|
||||
let store_handle = itself.get_data(&*STORE_WRAPPER).clone();
|
||||
FileLockEntryHandle::new(store_handle, sid).wrap()
|
||||
},
|
||||
}
|
||||
},
|
||||
on fail return NilClass::new().to_any_object()
|
||||
}
|
||||
}
|
||||
|
||||
// Get all FileLockEntry of a module from the store
|
||||
//
|
||||
// # Returns:
|
||||
//
|
||||
// On success: A Array[RFileLockEntry]
|
||||
// On error: Nil + Exception
|
||||
//
|
||||
fn retrieve_for_module(name: RString) -> AnyObject {
|
||||
use entry::FileLockEntryHandle as FLEH;
|
||||
use ruru::Array;
|
||||
|
||||
let name = typecheck!(name or return any NilClass::new()).to_string();
|
||||
|
||||
call_on_store! {
|
||||
store <- itself wrapped inside STORE_WRAPPER,
|
||||
operation {
|
||||
match store.retrieve_for_module(&name) {
|
||||
Err(e) => {
|
||||
trace_error(&e);
|
||||
VM::raise(Class::from_existing("RImagStoreWriteError"), e.description());
|
||||
NilClass::new().to_any_object()
|
||||
},
|
||||
Ok(iter) => {
|
||||
let store_handle = itself.get_data(&*STORE_WRAPPER).clone();
|
||||
iter.map(|sid| FLEH::new(store_handle.clone(), sid).wrap())
|
||||
.fold(Array::new(), |mut a, e| a.push(e))
|
||||
.to_any_object()
|
||||
},
|
||||
}
|
||||
},
|
||||
on fail return NilClass::new().to_any_object()
|
||||
}
|
||||
}
|
||||
|
||||
// Update a FileLockEntry in the store
|
||||
//
|
||||
// # Returns:
|
||||
//
|
||||
// On success: Nil
|
||||
// On error: Nil + Exception
|
||||
//
|
||||
fn update(fle: RFileLockEntryHandle) -> NilClass {
|
||||
let fle = typecheck!(fle).unwrap().fle_handle().clone();
|
||||
|
||||
call_on_store! {
|
||||
store <- itself wrapped inside STORE_WRAPPER,
|
||||
real_fle <- fetch fle,
|
||||
operation {
|
||||
let mut real_fle = real_fle; // rebind for mut
|
||||
if let Err(e) = store.update(&mut real_fle) {
|
||||
trace_error(&e);
|
||||
VM::raise(Class::from_existing("RImagStoreWriteError"), e.description());
|
||||
}
|
||||
NilClass::new()
|
||||
},
|
||||
on fail return NilClass::new()
|
||||
}
|
||||
}
|
||||
|
||||
// Delete a FileLockEntry from the store
|
||||
//
|
||||
// # Returns:
|
||||
//
|
||||
// On success: Nil
|
||||
// On error: Nil + Exception
|
||||
//
|
||||
fn delete(sid: RStoreId) -> NilClass {
|
||||
let sid = typecheck!(sid).unwrap().clone();
|
||||
|
||||
call_on_store! {
|
||||
store <- itself wrapped inside STORE_WRAPPER,
|
||||
operation {
|
||||
if let Err(e) = store.delete(sid) {
|
||||
trace_error(&e);
|
||||
VM::raise(Class::from_existing("RImagStoreWriteError"), e.description());
|
||||
}
|
||||
NilClass::new()
|
||||
},
|
||||
on fail return NilClass::new()
|
||||
}
|
||||
}
|
||||
|
||||
// Save a FileLockEntry in a new path inside the store, keep the RFileLockEntry
|
||||
//
|
||||
// # Returns:
|
||||
//
|
||||
// On success: Nil
|
||||
// On error: Nil + Exception
|
||||
//
|
||||
fn save_to(fle: RFileLockEntryHandle, sid: RStoreId) -> NilClass {
|
||||
let fle = typecheck!(fle).unwrap().fle_handle().clone();
|
||||
let sid = typecheck!(sid).unwrap().clone();
|
||||
|
||||
call_on_store! {
|
||||
store <- itself wrapped inside STORE_WRAPPER,
|
||||
real_fle <- fetch fle,
|
||||
operation {
|
||||
if let Err(e) = store.save_to(&real_fle, sid) {
|
||||
trace_error(&e);
|
||||
VM::raise(Class::from_existing("RImagStoreWriteError"), e.description());
|
||||
}
|
||||
NilClass::new()
|
||||
},
|
||||
on fail return NilClass::new()
|
||||
}
|
||||
}
|
||||
|
||||
// Save a FileLockEntry in a new path inside the store, move the RFileLockEntry
|
||||
//
|
||||
// # Returns:
|
||||
//
|
||||
// On success: Nil
|
||||
// On error: Nil + Exception
|
||||
//
|
||||
fn save_as(fle: RFileLockEntryHandle, sid: RStoreId) -> NilClass {
|
||||
let fle = typecheck!(fle).unwrap().fle_handle().clone();
|
||||
let sid = typecheck!(sid).unwrap().clone();
|
||||
|
||||
call_on_store! {
|
||||
store <- itself wrapped inside STORE_WRAPPER,
|
||||
real_fle <- fetch fle,
|
||||
operation {
|
||||
if let Err(e) = store.save_as(real_fle, sid) {
|
||||
trace_error(&e);
|
||||
VM::raise(Class::from_existing("RImagStoreWriteError"), e.description());
|
||||
}
|
||||
NilClass::new()
|
||||
},
|
||||
on fail return NilClass::new()
|
||||
}
|
||||
}
|
||||
|
||||
// Move one entry in the store to another place, by its ID
|
||||
//
|
||||
// # Returns:
|
||||
//
|
||||
// On success: Nil
|
||||
// On error: Nil + Exception
|
||||
//
|
||||
fn move_by_id(old: RStoreId, nw: RStoreId) -> NilClass {
|
||||
let old = typecheck!(old).unwrap().clone();
|
||||
let nw = typecheck!(nw).unwrap().clone();
|
||||
|
||||
call_on_store! {
|
||||
store <- itself wrapped inside STORE_WRAPPER,
|
||||
operation {
|
||||
if let Err(e) = store.move_by_id(old, nw) {
|
||||
trace_error(&e);
|
||||
VM::raise(Class::from_existing("RImagStoreWriteError"), e.description());
|
||||
}
|
||||
NilClass::new()
|
||||
},
|
||||
on fail return NilClass::new()
|
||||
}
|
||||
}
|
||||
|
||||
// Get the path of the store object
|
||||
//
|
||||
// # Returns:
|
||||
//
|
||||
// A RString
|
||||
//
|
||||
fn path() -> RString {
|
||||
call_on_store! {
|
||||
store <- itself wrapped inside STORE_WRAPPER,
|
||||
operation {
|
||||
store.path()
|
||||
.clone()
|
||||
.to_str()
|
||||
.map(RString::new)
|
||||
.unwrap_or(RString::new(""))
|
||||
},
|
||||
on fail return RString::new("")
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
pub fn setup() -> Class {
|
||||
let mut class = Class::new("RStoreHandle", None);
|
||||
class.define(|itself| {
|
||||
itself.def_self("new" , new);
|
||||
itself.def("create" , create);
|
||||
itself.def("retrieve" , retrieve);
|
||||
itself.def("get" , get);
|
||||
itself.def("retrieve_for_module" , retrieve_for_module);
|
||||
itself.def("update" , update);
|
||||
itself.def("delete" , delete);
|
||||
itself.def("save_to" , save_to);
|
||||
itself.def("save_as" , save_as);
|
||||
itself.def("move_by_id" , move_by_id);
|
||||
itself.def("path" , path);
|
||||
});
|
||||
class
|
||||
}
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
//
|
||||
// imag - the personal information management suite for the commandline
|
||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; version
|
||||
// 2.1 of the License.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
#[allow(unused_variables)]
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use ruru::{Class, Object, AnyObject, Boolean, RString, NilClass, VerifiedObject, VM};
|
||||
|
||||
use libimagstore::storeid::StoreId;
|
||||
use util::Unwrap;
|
||||
use util::Wrap;
|
||||
|
||||
wrappable_struct!(StoreId, StoreIdWrapper, STOREID_WRAPPER);
|
||||
class!(RStoreId);
|
||||
impl_wrap!(StoreId => STOREID_WRAPPER);
|
||||
impl_unwrap!(RStoreId => StoreId => STOREID_WRAPPER);
|
||||
impl_verified_object!(RStoreId);
|
||||
|
||||
|
||||
methods!(
|
||||
RStoreId,
|
||||
itself,
|
||||
|
||||
fn r_storeid_new(base: RString, id: RString) -> AnyObject {
|
||||
let base = match base.map(|b| b.to_string()).map(PathBuf::from) {
|
||||
Ok(base) => base,
|
||||
Err(e) => {
|
||||
// TODO: Exception!
|
||||
error!("Building StoreId object failed: {:?}", e);
|
||||
return AnyObject::from(NilClass::new().value());
|
||||
},
|
||||
};
|
||||
|
||||
let id = match id.map(|id| id.to_string()).map(PathBuf::from) {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
// TODO: Exception!
|
||||
error!("Building StoreId object failed: {:?}", e);
|
||||
return AnyObject::from(NilClass::new().value());
|
||||
},
|
||||
};
|
||||
|
||||
match StoreId::new(Some(base), id) {
|
||||
Ok(sid) => Class::from_existing("RStoreId").wrap_data(sid, &*STOREID_WRAPPER),
|
||||
Err(e) => {
|
||||
// TODO: Exception!
|
||||
error!("Building StoreId object failed: {:?}", e);
|
||||
return AnyObject::from(NilClass::new().value());
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn r_storeid_new_baseless(id: RString) -> AnyObject {
|
||||
let id = match id.map(|id| id.to_string()).map(PathBuf::from) {
|
||||
Ok(id) => id,
|
||||
Err(e) => {
|
||||
// TODO: Exception!
|
||||
error!("Building StoreId object failed: {:?}", e);
|
||||
return AnyObject::from(NilClass::new().value());
|
||||
},
|
||||
};
|
||||
|
||||
match StoreId::new(None, id) {
|
||||
Ok(sid) => Class::from_existing("RStoreId").wrap_data(sid, &*STOREID_WRAPPER),
|
||||
Err(e) => {
|
||||
// TODO: Exception!
|
||||
error!("Building StoreId object failed: {:?}", e);
|
||||
return AnyObject::from(NilClass::new().value());
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn r_storeid_without_base() -> RStoreId {
|
||||
let withoutbase : StoreId = itself.get_data(&*STOREID_WRAPPER).clone().without_base();
|
||||
Class::from_existing("RStoreId").wrap_data(withoutbase, &*STOREID_WRAPPER)
|
||||
}
|
||||
|
||||
fn r_storeid_with_base(base: RString) -> AnyObject {
|
||||
let base : PathBuf = match base.map(|b| b.to_string()).map(PathBuf::from) {
|
||||
Ok(pb) => pb,
|
||||
Err(e) => {
|
||||
// TODO: Exception!
|
||||
error!("Error: {:?}", e);
|
||||
return AnyObject::from(NilClass::new().value());
|
||||
},
|
||||
};
|
||||
let withoutbase : StoreId = itself.get_data(&*STOREID_WRAPPER).clone().with_base(base);
|
||||
Class::from_existing("RStoreId").wrap_data(withoutbase, &*STOREID_WRAPPER)
|
||||
}
|
||||
|
||||
fn r_storeid_into_pathbuf() -> AnyObject {
|
||||
itself.get_data(&*STOREID_WRAPPER)
|
||||
.clone()
|
||||
.into_pathbuf()
|
||||
// TODO: No unwraps
|
||||
.map(|pb| pb.to_str().map(String::from).unwrap())
|
||||
.as_ref()
|
||||
.map(|s| AnyObject::from(RString::new(s).value()))
|
||||
// TODO: Exception!
|
||||
.unwrap_or(AnyObject::from(NilClass::new().value()))
|
||||
}
|
||||
|
||||
fn r_storeid_exists() -> Boolean {
|
||||
use std::error::Error;
|
||||
|
||||
match itself.get_data(&*STOREID_WRAPPER).exists() {
|
||||
Ok(bool) => Boolean::new(bool),
|
||||
Err(e) => {
|
||||
VM::raise(Class::from_existing("RuntimeError"), e.description());
|
||||
Boolean::new(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn r_storeid_to_str() -> AnyObject {
|
||||
itself.get_data(&*STOREID_WRAPPER)
|
||||
.to_str()
|
||||
.as_ref()
|
||||
.map(|s| AnyObject::from(RString::new(s).value()))
|
||||
// TODO: Exception!
|
||||
.unwrap_or(AnyObject::from(NilClass::new().value()))
|
||||
}
|
||||
|
||||
fn r_storeid_local() -> RString {
|
||||
let local = itself.get_data(&*STOREID_WRAPPER).local();
|
||||
let local = local.to_str().unwrap(); // TODO: No unwraps
|
||||
RString::new(local)
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
pub fn setup() -> Class {
|
||||
let mut class = Class::new("RStoreId", None);
|
||||
class.define(|itself| {
|
||||
itself.def_self("new" , r_storeid_new);
|
||||
itself.def_self("new_baseless" , r_storeid_new_baseless);
|
||||
|
||||
itself.def("without_base" , r_storeid_without_base);
|
||||
itself.def("with_base" , r_storeid_with_base);
|
||||
itself.def("into_pathbuf" , r_storeid_into_pathbuf);
|
||||
itself.def("exists" , r_storeid_exists);
|
||||
itself.def("to_str" , r_storeid_to_str);
|
||||
itself.def("local" , r_storeid_local);
|
||||
});
|
||||
class
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
//
|
||||
// imag - the personal information management suite for the commandline
|
||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; version
|
||||
// 2.1 of the License.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
// Toml -> Ruby translation primitives
|
||||
|
||||
use ruru::{Object, AnyObject, RString, Fixnum, Float, Boolean, Hash, Array};
|
||||
use toml::Value;
|
||||
|
||||
pub trait AsRuby : Sized {
|
||||
fn as_ruby(&self) -> AnyObject;
|
||||
}
|
||||
|
||||
pub trait IntoRuby : AsRuby {
|
||||
fn into_ruby(self) -> AnyObject {
|
||||
self.as_ruby()
|
||||
}
|
||||
}
|
||||
impl<T: AsRuby> IntoRuby for T { }
|
||||
|
||||
impl AsRuby for Value {
|
||||
|
||||
fn as_ruby(&self) -> AnyObject {
|
||||
match *self {
|
||||
Value::String(ref s) => RString::new(&s).to_any_object(),
|
||||
Value::Integer(i) => Fixnum::new(i).to_any_object(),
|
||||
Value::Float(f) => Float::new(f).to_any_object(),
|
||||
Value::Boolean(b) => Boolean::new(b).to_any_object(),
|
||||
Value::Datetime(ref s) => RString::new(&s).to_any_object(),
|
||||
Value::Array(ref a) => {
|
||||
let mut arr = Array::new();
|
||||
for obj in a.into_iter().map(AsRuby::as_ruby) {
|
||||
arr.push(obj);
|
||||
}
|
||||
arr.to_any_object()
|
||||
},
|
||||
Value::Table(ref t) => {
|
||||
let mut h = Hash::new();
|
||||
for (k, v) in t.into_iter() {
|
||||
let key = RString::new(k).to_any_object();
|
||||
let v = v.as_ruby();
|
||||
h.store(key, v);
|
||||
}
|
||||
h.to_any_object()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
//
|
||||
// imag - the personal information management suite for the commandline
|
||||
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public
|
||||
// License as published by the Free Software Foundation; version
|
||||
// 2.1 of the License.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
//
|
||||
|
||||
use ruru::AnyObject;
|
||||
pub trait Wrap {
|
||||
fn wrap(self) -> AnyObject;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_wrap {
|
||||
($target:ty => $wrapper:path) => {
|
||||
impl Wrap for $target {
|
||||
fn wrap(self) -> AnyObject {
|
||||
Class::from_existing(concat!("R", stringify!($target)))
|
||||
.wrap_data(self, &*($wrapper))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Unwrap {
|
||||
type Target;
|
||||
fn unwrap<'a>(&'a self) -> &'a mut Self::Target;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_unwrap {
|
||||
($from:ty => $to:ty => $wrapper:path) => {
|
||||
impl Unwrap for $from {
|
||||
type Target = $to;
|
||||
fn unwrap<'a>(&'a self) -> &'a mut $to {
|
||||
self.get_data(&*($wrapper))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_verified_object {
|
||||
($objname: ty) => {
|
||||
impl VerifiedObject for $objname {
|
||||
fn is_correct_type<T: Object>(object: &T) -> bool {
|
||||
object.class() == Class::from_existing(stringify!($objname))
|
||||
}
|
||||
|
||||
fn error_message() -> &'static str {
|
||||
concat!("Not a ", stringify!($objname), " object")
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Helper macro to simplify type checking in the ruby-interfacing functions.
|
||||
///
|
||||
/// # Return
|
||||
///
|
||||
/// If called with only the object to check, this returns NIL after raising an exception.
|
||||
/// If called with more arguments, the other things will be returned.
|
||||
/// E.G.:
|
||||
///
|
||||
/// ```ignore
|
||||
/// let obj1 = typecheck!(obj1); // returns `obj` or raises exception
|
||||
///
|
||||
/// // returns `obj` or raises exception and returns AnyObject (Boolean -> false):
|
||||
/// let obj2 = typecheck!(obj2 or return any Boolean::new(false));
|
||||
///
|
||||
/// // returns `obj` or raises excpetion and returns Boolean -> false
|
||||
/// let obj3 = typecheck!(obj3 or return Boolean::new(false));
|
||||
/// ```
|
||||
///
|
||||
#[macro_export]
|
||||
macro_rules! typecheck {
|
||||
($obj: ident) => { typecheck!($obj or return NilClass::new()) };
|
||||
($obj: ident or return any $els: expr) => { typecheck!($obj or return $els.to_any_object()) };
|
||||
($obj: ident or return $els: expr) => {
|
||||
match $obj {
|
||||
Ok(o) => o,
|
||||
Err(e) => {
|
||||
VM::raise(e.to_exception(), e.description());
|
||||
return $els
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in a new issue