Remove libimagruby

To quick-fix the master branch.
This commit is contained in:
Matthias Beyer 2017-05-02 16:00:14 +02:00
parent 7e3c9467e7
commit 2b2ef72b69
24 changed files with 2 additions and 2059 deletions

View File

@ -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

View File

@ -21,7 +21,6 @@ members = [
"libimagnotes",
"libimagref",
"libimagrt",
"libimagruby",
"libimagstore",
"libimagstorestdhook",
"libimagtimeui",

View File

@ -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]"

View File

@ -7,7 +7,6 @@ let
];
dependencies = with pkgs; [
ruby
bundler
cmake
curl

View File

@ -1,5 +0,0 @@
.bundle
Gemfile.lock
lib/liblibimagruby.so
vendor/bundle
libimagruby*.tar.gz

View File

@ -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"

View File

@ -1,4 +0,0 @@
# frozen_string_literal: true
source "https://rubygems.org"
gemspec

View File

@ -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

View File

@ -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.

View File

@ -1,5 +0,0 @@
require "bundler/gem_tasks"
require 'thermite/tasks'
Thermite::Tasks.new(cargo_project_path: "..", cargo_workspace_member: "libimagruby")

View File

@ -1,5 +0,0 @@
require 'thermite/tasks'
Thermite::Tasks.new(cargo_project_path: "..", cargo_workspace_member: "libimagruby")
task default: %w(thermite:build)

View File

@ -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

View File

@ -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

View File

@ -1,3 +0,0 @@
module Imag
VERSION = "0.1.0"
end

View File

@ -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()))
};
}

View File

@ -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))
}

View File

@ -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));
}

View File

@ -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
}

View File

@ -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();
}

View File

@ -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())
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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()
},
}
}
}

View File

@ -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
},
}
};
}