Remove libimagruby
To quick-fix the master branch.
This commit is contained in:
parent
7e3c9467e7
commit
2b2ef72b69
24 changed files with 2 additions and 2059 deletions
18
.travis.yml
18
.travis.yml
|
@ -10,23 +10,9 @@ language: rust
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- rust: 1.13.0
|
- rust: 1.13.0
|
||||||
env: IMAG_RUBY_VERSION=2.3.3
|
|
||||||
- rust: 1.13.0
|
|
||||||
env: IMAG_RUBY_VERSION=2.4.0
|
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
cargo: true
|
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:
|
before_script:
|
||||||
- |
|
- |
|
||||||
|
@ -44,7 +30,6 @@ addons:
|
||||||
- libcurl4-openssl-dev
|
- libcurl4-openssl-dev
|
||||||
- libdw-dev
|
- libdw-dev
|
||||||
- libelf-dev
|
- libelf-dev
|
||||||
- libruby
|
|
||||||
- libzzip-dev
|
- libzzip-dev
|
||||||
- make
|
- make
|
||||||
- tree
|
- tree
|
||||||
|
@ -71,6 +56,3 @@ env:
|
||||||
global:
|
global:
|
||||||
- THERMITE_DEBUG_FILENAME=/tmp/thermite-debug.log
|
- 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=
|
- 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",
|
"libimagnotes",
|
||||||
"libimagref",
|
"libimagref",
|
||||||
"libimagrt",
|
"libimagrt",
|
||||||
"libimagruby",
|
|
||||||
"libimagstore",
|
"libimagstore",
|
||||||
"libimagstorestdhook",
|
"libimagstorestdhook",
|
||||||
"libimagtimeui",
|
"libimagtimeui",
|
||||||
|
|
10
Makefile
10
Makefile
|
@ -47,18 +47,12 @@ bin: $(BIN_TARGETS) imag-bin
|
||||||
|
|
||||||
bin-test: $(BIN_TARGET_TESTS) imag-bin
|
bin-test: $(BIN_TARGET_TESTS) imag-bin
|
||||||
|
|
||||||
lib: $(LIB_TARGETS) lib-imag-ruby-tarball
|
lib: $(LIB_TARGETS)
|
||||||
@$(ECHO) "\t[ALLLIB ]"
|
@$(ECHO) "\t[ALLLIB ]"
|
||||||
|
|
||||||
lib-test: $(LIB_TARGETS_TEST)
|
lib-test: $(LIB_TARGETS_TEST)
|
||||||
|
|
||||||
lib-imag-ruby-tarball:
|
test: bin-test lib-test
|
||||||
@$(MAKE) -C libimagruby tarball
|
|
||||||
|
|
||||||
lib-imag-ruby-test:
|
|
||||||
@$(MAKE) -C libimagruby test
|
|
||||||
|
|
||||||
test: bin-test lib-test lib-imag-ruby-test
|
|
||||||
|
|
||||||
install: $(INSTALL_TARGETS) imag-bin-install
|
install: $(INSTALL_TARGETS) imag-bin-install
|
||||||
@$(ECHO) "\t[INSTALL]"
|
@$(ECHO) "\t[INSTALL]"
|
||||||
|
|
|
@ -7,7 +7,6 @@ let
|
||||||
];
|
];
|
||||||
|
|
||||||
dependencies = with pkgs; [
|
dependencies = with pkgs; [
|
||||||
ruby
|
|
||||||
bundler
|
bundler
|
||||||
cmake
|
cmake
|
||||||
curl
|
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