openzip 0.1.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +10 -0
- data/.simplecov +2 -1
- data/.travis.yml +10 -2
- data/Gemfile +1 -0
- data/README.md +24 -5
- data/benchmarking/iterations.md +48 -0
- data/benchmarking/memory.md +50 -0
- data/lib/openzip/version.rb +1 -1
- data/lib/openzip.rb +8 -2
- data/openzip.gemspec +4 -2
- data/source/extconf.rb +1 -1
- data/source/src/extractor.rs +93 -0
- data/source/src/lib.rs +17 -81
- metadata +9 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f451c024999099c3a92d2c1a2d8a4188f8579b9
|
4
|
+
data.tar.gz: 3a115ee87ca4b72a1c6343c82ddfa7b08a0e1a10
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ebd30eaf00e393a0e76242e6a0884a37b30e790084e549b587cf090990dfc2250d74f9506f7cb8a4d7a44bcdb0c035e622ba3bff9b23cf821803fe8ec6d79396
|
7
|
+
data.tar.gz: 73ad5ee53c7102c29cc45b50694ab9248ed1c3df021c695e7b55d2e01f9211e44e272edb77079e1b65fb017ae6736f34ef7af6ea43bd779564ea1619daf1091d
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -32,6 +32,10 @@ Metrics/LineLength:
|
|
32
32
|
Description: 'Limit lines to 120 characters.'
|
33
33
|
Max: 120
|
34
34
|
|
35
|
+
Metrics/BlockLength:
|
36
|
+
Exclude:
|
37
|
+
- spec/**/*.rb
|
38
|
+
|
35
39
|
Lint/EndAlignment:
|
36
40
|
EnforcedStyleAlignWith: variable
|
37
41
|
SupportedStylesAlignWith:
|
@@ -54,3 +58,9 @@ Style/StringMethods:
|
|
54
58
|
RSpec/MessageSpies:
|
55
59
|
Enabled: true
|
56
60
|
EnforcedStyle: receive
|
61
|
+
|
62
|
+
RSpec/MultipleExpectations:
|
63
|
+
Enabled: false
|
64
|
+
|
65
|
+
RSpec/NestedGroups:
|
66
|
+
Enabled: false
|
data/.simplecov
CHANGED
data/.travis.yml
CHANGED
@@ -2,11 +2,19 @@ language: ruby
|
|
2
2
|
cache: bundler
|
3
3
|
sudo: required
|
4
4
|
|
5
|
+
os:
|
6
|
+
- linux
|
7
|
+
- osx
|
8
|
+
|
5
9
|
rvm:
|
6
|
-
- 2.
|
10
|
+
- 2.0.0
|
11
|
+
- 2.1.10
|
12
|
+
- 2.2.5
|
13
|
+
- 2.3.3
|
14
|
+
- 2.4.0
|
7
15
|
|
8
16
|
before_install:
|
9
|
-
- gem install bundler
|
17
|
+
- gem install bundler
|
10
18
|
- bin/compile
|
11
19
|
|
12
20
|
script:
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -6,23 +6,42 @@
|
|
6
6
|
[](https://github.com/ilyasgaraev/openzip)
|
7
7
|
|
8
8
|
|
9
|
-
**Openzip** is a Ruby library for fast extract Zip files.
|
9
|
+
**Openzip** is a Ruby library (written in Rust) for fast extract Zip files.
|
10
10
|
|
11
11
|
## Usage
|
12
12
|
|
13
|
+
Before you begin, you need to install Rust (with Cargo) on your system (see [Requirements](#requirements)).
|
14
|
+
|
13
15
|
```ruby
|
14
|
-
|
15
|
-
|
16
|
+
Openzip.extract("path/to/file.zip", "extract/path")
|
17
|
+
# returns true if the method successfully executed; otherwise, false
|
18
|
+
```
|
16
19
|
|
17
|
-
|
20
|
+
The **DEBUG** environment variable can be used to enable debug logs:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
# DEBUG=true
|
24
|
+
Openzip.extract("wrong/path/file.zip", "extract/path")
|
25
|
+
# Error: No such file or directory (os error 2)
|
26
|
+
# => false
|
18
27
|
```
|
19
28
|
|
29
|
+
## Requirements
|
30
|
+
|
31
|
+
* Rust and Cargo ([https://www.rust-lang.org/en-US/install.html](https://www.rust-lang.org/en-US/install.html))
|
32
|
+
* Ruby 2.0 or greater
|
33
|
+
|
34
|
+
## Benchmarking
|
35
|
+
|
36
|
+
* Memory usage: [benchmarking/memory.md](benchmarking/memory.md)
|
37
|
+
* Iterations per second: [benchmarking/iterations.md](benchmarking/iterations.md)
|
38
|
+
|
20
39
|
## Installation
|
21
40
|
|
22
41
|
Add this line to your application's Gemfile:
|
23
42
|
|
24
43
|
```ruby
|
25
|
-
gem
|
44
|
+
gem "openzip"
|
26
45
|
```
|
27
46
|
|
28
47
|
And then execute:
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Iterations per second
|
2
|
+
|
3
|
+
**Openzip** vs **rubyzip**.
|
4
|
+
|
5
|
+
---
|
6
|
+
## Zip file
|
7
|
+
|
8
|
+
### File info
|
9
|
+
* **Type:** zip
|
10
|
+
* **Files in archive:** 2500
|
11
|
+
* **Size:** 6 500 079 bytes (6,5 MB)
|
12
|
+
|
13
|
+
### Results
|
14
|
+
|
15
|
+
```
|
16
|
+
Warming up --------------------------------------
|
17
|
+
openzip 1.000 i/100ms
|
18
|
+
rubyzip 1.000 i/100ms
|
19
|
+
Calculating -------------------------------------
|
20
|
+
openzip 0.841 (± 0.0%) i/s - 5.000 in 5.943962s
|
21
|
+
rubyzip 0.369 (± 0.0%) i/s - 2.000 in 5.416802s
|
22
|
+
|
23
|
+
Comparison:
|
24
|
+
openzip: 0.8 i/s
|
25
|
+
rubyzip: 0.4 i/s - 2.28x slower
|
26
|
+
```
|
27
|
+
|
28
|
+
---
|
29
|
+
## Excel file
|
30
|
+
|
31
|
+
### File info
|
32
|
+
* **Type:** xlsx
|
33
|
+
* **Files in archive:** 13
|
34
|
+
* **Size:** 775 231 bytes (778 KB)
|
35
|
+
* **Filled rows:** 5000
|
36
|
+
|
37
|
+
```
|
38
|
+
Warming up --------------------------------------
|
39
|
+
openzip 1.000 i/100ms
|
40
|
+
rubyzip 1.000 i/100ms
|
41
|
+
Calculating -------------------------------------
|
42
|
+
openzip 18.270 (± 5.5%) i/s - 91.000 in 5.000976s
|
43
|
+
rubyzip 13.548 (± 7.4%) i/s - 68.000 in 5.033290s
|
44
|
+
|
45
|
+
Comparison:
|
46
|
+
openzip: 18.3 i/s
|
47
|
+
rubyzip: 13.5 i/s - 1.35x slower
|
48
|
+
```
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Memory usage
|
2
|
+
|
3
|
+
**Openzip** vs **rubyzip**.
|
4
|
+
|
5
|
+
---
|
6
|
+
## Zip file
|
7
|
+
|
8
|
+
### File info
|
9
|
+
* **Type:** zip
|
10
|
+
* **Files in archive:** 2500
|
11
|
+
* **Size:** 6 500 079 bytes (6,5 MB)
|
12
|
+
|
13
|
+
### Results
|
14
|
+
|
15
|
+
```
|
16
|
+
Calculating -------------------------------------
|
17
|
+
openzip 627.000 memsize ( 40.000 retained)
|
18
|
+
10.000 objects ( 1.000 retained)
|
19
|
+
3.000 strings ( 0.000 retained)
|
20
|
+
rubyzip 304.757M memsize ( 120.000 retained)
|
21
|
+
866.162k objects ( 3.000 retained)
|
22
|
+
50.000 strings ( 2.000 retained)
|
23
|
+
|
24
|
+
Comparison:
|
25
|
+
openzip: 627 allocated
|
26
|
+
rubyzip: 304757473 allocated - 486056.58x more
|
27
|
+
```
|
28
|
+
|
29
|
+
---
|
30
|
+
## Excel file
|
31
|
+
|
32
|
+
### File info
|
33
|
+
* **Type:** xlsx
|
34
|
+
* **Files in archive:** 13
|
35
|
+
* **Size:** 775 231 bytes (778 KB)
|
36
|
+
* **Filled rows:** 5000
|
37
|
+
|
38
|
+
```
|
39
|
+
Calculating -------------------------------------
|
40
|
+
openzip 626.000 memsize ( 40.000 retained)
|
41
|
+
10.000 objects ( 1.000 retained)
|
42
|
+
3.000 strings ( 0.000 retained)
|
43
|
+
rubyzip 62.955M memsize ( 40.000 retained)
|
44
|
+
2.763k objects ( 1.000 retained)
|
45
|
+
50.000 strings ( 0.000 retained)
|
46
|
+
|
47
|
+
Comparison:
|
48
|
+
openzip: 626 allocated
|
49
|
+
rubyzip: 62954673 allocated - 100566.57x more
|
50
|
+
```
|
data/lib/openzip/version.rb
CHANGED
data/lib/openzip.rb
CHANGED
@@ -5,11 +5,17 @@ module Openzip
|
|
5
5
|
extend Fiddle::Importer
|
6
6
|
|
7
7
|
def self.lib_ext
|
8
|
-
raise "Sorry,
|
8
|
+
raise NotImplementedError, "Sorry, Windows is not supported" if RUBY_PLATFORM =~ /win32/
|
9
9
|
|
10
10
|
RUBY_PLATFORM =~ /darwin/ ? "dylib" : "so"
|
11
11
|
end
|
12
12
|
|
13
13
|
dlload "#{File.dirname(__FILE__)}/../source/target/release/libopenzip.#{lib_ext}"
|
14
|
-
|
14
|
+
|
15
|
+
def self.extract(zippath, outdirpath)
|
16
|
+
extract_rust(zippath, outdirpath) != 0
|
17
|
+
end
|
18
|
+
|
19
|
+
extern "char extract_rust(char*, char*)"
|
20
|
+
private_class_method :extract_rust
|
15
21
|
end
|
data/openzip.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Ilyas Garaev"]
|
10
10
|
spec.email = ["vearagi@gmail.com"]
|
11
11
|
|
12
|
-
spec.summary = "Openzip is a Ruby library for fast reading Zip files."
|
13
|
-
spec.description = "Openzip is a Ruby library for fast reading Zip files."
|
12
|
+
spec.summary = "Openzip is a Ruby library (written in Rust) for fast reading Zip files."
|
13
|
+
spec.description = "Openzip is a Ruby library (written in Rust) for fast reading Zip files."
|
14
14
|
spec.homepage = "https://github.com/ilyasgaraev/openzip"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
@@ -20,6 +20,8 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.extensions = Dir["source/extconf.rb"]
|
22
22
|
|
23
|
+
spec.required_ruby_version = "~> 2.0"
|
24
|
+
|
23
25
|
spec.add_development_dependency "bundler", "~> 1.13"
|
24
26
|
spec.add_development_dependency "pry", "~> 0.10"
|
25
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
data/source/extconf.rb
CHANGED
@@ -0,0 +1,93 @@
|
|
1
|
+
extern crate zip;
|
2
|
+
|
3
|
+
use std::io;
|
4
|
+
use std::fs;
|
5
|
+
use std::path::{Path, PathBuf, Component};
|
6
|
+
use std::error::Error;
|
7
|
+
|
8
|
+
#[cfg(unix)]
|
9
|
+
use std::os::unix::fs::PermissionsExt;
|
10
|
+
|
11
|
+
pub fn run(zippath: &Path, outdirpath: &Path) -> Result<bool, Box<Error>>
|
12
|
+
{
|
13
|
+
let file = try!(fs::File::open(&zippath));
|
14
|
+
try!(create_directory(&outdirpath, None));
|
15
|
+
|
16
|
+
let mut archive = try!(zip::ZipArchive::new(file));
|
17
|
+
|
18
|
+
for i in 0..archive.len()
|
19
|
+
{
|
20
|
+
let mut file = archive.by_index(i).unwrap();
|
21
|
+
let outpath = sanitize_filename(file.name(), outdirpath);
|
22
|
+
|
23
|
+
try!(create_directory(outpath.parent().unwrap_or(Path::new("")), None));
|
24
|
+
|
25
|
+
let perms = convert_permissions(file.unix_mode());
|
26
|
+
|
27
|
+
if file.name().ends_with("/") {
|
28
|
+
try!(create_directory(&outpath, perms));
|
29
|
+
} else {
|
30
|
+
try!(write_file(&mut file, &outpath, perms));
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
Ok(true)
|
35
|
+
}
|
36
|
+
|
37
|
+
#[cfg(unix)]
|
38
|
+
fn convert_permissions(mode: Option<u32>) -> Option<fs::Permissions>
|
39
|
+
{
|
40
|
+
match mode {
|
41
|
+
Some(mode) => Some(fs::Permissions::from_mode(mode)),
|
42
|
+
None => None,
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
#[cfg(not(unix))]
|
47
|
+
fn convert_permissions(_mode: Option<u32>) -> Option<fs::Permissions>
|
48
|
+
{
|
49
|
+
None
|
50
|
+
}
|
51
|
+
|
52
|
+
fn write_file(file: &mut zip::read::ZipFile, outpath: &Path, perms: Option<fs::Permissions>) -> Result<(), Box<Error>>
|
53
|
+
{
|
54
|
+
let mut outfile = try!(fs::File::create(&outpath));
|
55
|
+
try!(io::copy(file, &mut outfile));
|
56
|
+
|
57
|
+
if let Some(perms) = perms {
|
58
|
+
try!(fs::set_permissions(outpath, perms));
|
59
|
+
}
|
60
|
+
|
61
|
+
Ok(())
|
62
|
+
}
|
63
|
+
|
64
|
+
fn create_directory(outpath: &Path, perms: Option<fs::Permissions>) -> Result<(), Box<Error>>
|
65
|
+
{
|
66
|
+
try!(fs::create_dir_all(&outpath));
|
67
|
+
|
68
|
+
if let Some(perms) = perms {
|
69
|
+
try!(fs::set_permissions(outpath, perms));
|
70
|
+
}
|
71
|
+
|
72
|
+
Ok(())
|
73
|
+
}
|
74
|
+
|
75
|
+
fn sanitize_filename(filename: &str, outdir: &Path) -> PathBuf
|
76
|
+
{
|
77
|
+
let no_null_filename = match filename.find('\0') {
|
78
|
+
Some(index) => &filename[0..index],
|
79
|
+
None => filename,
|
80
|
+
};
|
81
|
+
|
82
|
+
let filepath = Path::new(no_null_filename)
|
83
|
+
.components()
|
84
|
+
.filter(|component| *component != Component::ParentDir)
|
85
|
+
.fold(PathBuf::new(), |mut path, ref cur| {
|
86
|
+
path.push(cur.as_os_str());
|
87
|
+
path
|
88
|
+
});
|
89
|
+
|
90
|
+
let mut outdirbuf = PathBuf::from(outdir);
|
91
|
+
outdirbuf.push(filepath);
|
92
|
+
return outdirbuf.to_path_buf();
|
93
|
+
}
|
data/source/src/lib.rs
CHANGED
@@ -1,94 +1,30 @@
|
|
1
|
-
extern crate zip;
|
2
1
|
extern crate libc;
|
3
2
|
|
4
|
-
|
5
|
-
use std::fs;
|
6
|
-
use std::path::{Path, PathBuf, Component};
|
7
|
-
use std::ffi::CStr;
|
3
|
+
mod extractor;
|
8
4
|
|
9
|
-
|
10
|
-
use std::
|
5
|
+
use std::env;
|
6
|
+
use std::path::Path;
|
7
|
+
use std::ffi::CStr;
|
11
8
|
|
12
9
|
#[no_mangle]
|
13
|
-
pub extern fn
|
14
|
-
let zname = Path::new(rust_string(zippath));
|
15
|
-
let outdir = Path::new(rust_string(outdirpath));
|
16
|
-
|
17
|
-
create_directory(&outdir, None);
|
18
|
-
let file = fs::File::open(&zname).unwrap();
|
19
|
-
|
20
|
-
let mut archive = zip::ZipArchive::new(file).unwrap();
|
21
|
-
|
22
|
-
for i in 0..archive.len()
|
23
|
-
{
|
24
|
-
let mut file = archive.by_index(i).unwrap();
|
25
|
-
let outpath = sanitize_filename(file.name(), outdir);
|
26
|
-
|
27
|
-
create_directory(outpath.parent().unwrap_or(Path::new("")), None);
|
28
|
-
|
29
|
-
let perms = convert_permissions(file.unix_mode());
|
30
|
-
|
31
|
-
if (&*file.name()).ends_with("/") {
|
32
|
-
create_directory(&outpath, perms);
|
33
|
-
}
|
34
|
-
else {
|
35
|
-
write_file(&mut file, &outpath, perms);
|
36
|
-
}
|
37
|
-
}
|
38
|
-
}
|
39
|
-
|
40
|
-
fn rust_string(r_string: *const libc::c_char) -> &'static str {
|
41
|
-
unsafe { CStr::from_ptr(r_string) }.to_str().unwrap()
|
42
|
-
}
|
43
|
-
|
44
|
-
#[cfg(unix)]
|
45
|
-
fn convert_permissions(mode: Option<u32>) -> Option<fs::Permissions>
|
10
|
+
pub extern fn extract_rust(zip: *const libc::c_char, outdir: *const libc::c_char) -> bool
|
46
11
|
{
|
47
|
-
|
48
|
-
|
49
|
-
None => None,
|
50
|
-
}
|
51
|
-
}
|
12
|
+
let zippath = Path::new(rust_string(zip));
|
13
|
+
let outdirpath = Path::new(rust_string(outdir));
|
52
14
|
|
53
|
-
|
54
|
-
|
55
|
-
{
|
56
|
-
|
57
|
-
}
|
58
|
-
|
59
|
-
fn write_file(file: &mut zip::read::ZipFile, outpath: &Path, perms: Option<fs::Permissions>)
|
60
|
-
{
|
61
|
-
let mut outfile = fs::File::create(&outpath).unwrap();
|
62
|
-
io::copy(file, &mut outfile).unwrap();
|
63
|
-
if let Some(perms) = perms {
|
64
|
-
fs::set_permissions(outpath, perms).unwrap();
|
65
|
-
}
|
66
|
-
}
|
15
|
+
return match extractor::run(zippath, outdirpath) {
|
16
|
+
Ok(_) => true,
|
17
|
+
Err(e) => {
|
18
|
+
if env::var("DEBUG").ok() == Some(String::from("true")) {
|
19
|
+
println!("Error: {}", e);
|
20
|
+
}
|
67
21
|
|
68
|
-
|
69
|
-
|
70
|
-
fs::create_dir_all(&outpath).unwrap();
|
71
|
-
if let Some(perms) = perms {
|
72
|
-
fs::set_permissions(outpath, perms).unwrap();
|
22
|
+
false
|
23
|
+
}
|
73
24
|
}
|
74
25
|
}
|
75
26
|
|
76
|
-
fn
|
27
|
+
fn rust_string(r_string: *const libc::c_char) -> &'static str
|
77
28
|
{
|
78
|
-
|
79
|
-
Some(index) => &filename[0..index],
|
80
|
-
None => filename,
|
81
|
-
};
|
82
|
-
|
83
|
-
let filepath = Path::new(no_null_filename)
|
84
|
-
.components()
|
85
|
-
.filter(|component| *component != Component::ParentDir)
|
86
|
-
.fold(PathBuf::new(), |mut path, ref cur| {
|
87
|
-
path.push(cur.as_os_str());
|
88
|
-
path
|
89
|
-
});
|
90
|
-
|
91
|
-
let mut outdirbuf = PathBuf::from(outdir);
|
92
|
-
outdirbuf.push(filepath);
|
93
|
-
return outdirbuf.to_path_buf();
|
29
|
+
unsafe { CStr::from_ptr(r_string) }.to_str().unwrap()
|
94
30
|
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openzip
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ilyas Garaev
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-03-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,7 +66,7 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '3.0'
|
69
|
-
description: Openzip is a Ruby library for fast reading Zip files.
|
69
|
+
description: Openzip is a Ruby library (written in Rust) for fast reading Zip files.
|
70
70
|
email:
|
71
71
|
- vearagi@gmail.com
|
72
72
|
executables: []
|
@@ -84,6 +84,8 @@ files:
|
|
84
84
|
- LICENSE
|
85
85
|
- README.md
|
86
86
|
- Rakefile
|
87
|
+
- benchmarking/iterations.md
|
88
|
+
- benchmarking/memory.md
|
87
89
|
- bin/bundle-audit
|
88
90
|
- bin/ci
|
89
91
|
- bin/compile
|
@@ -100,6 +102,7 @@ files:
|
|
100
102
|
- source/Cargo.toml
|
101
103
|
- source/Makefile
|
102
104
|
- source/extconf.rb
|
105
|
+
- source/src/extractor.rs
|
103
106
|
- source/src/lib.rs
|
104
107
|
homepage: https://github.com/ilyasgaraev/openzip
|
105
108
|
licenses:
|
@@ -111,9 +114,9 @@ require_paths:
|
|
111
114
|
- lib
|
112
115
|
required_ruby_version: !ruby/object:Gem::Requirement
|
113
116
|
requirements:
|
114
|
-
- - "
|
117
|
+
- - "~>"
|
115
118
|
- !ruby/object:Gem::Version
|
116
|
-
version: '0'
|
119
|
+
version: '2.0'
|
117
120
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
121
|
requirements:
|
119
122
|
- - ">="
|
@@ -124,5 +127,5 @@ rubyforge_project:
|
|
124
127
|
rubygems_version: 2.6.8
|
125
128
|
signing_key:
|
126
129
|
specification_version: 4
|
127
|
-
summary: Openzip is a Ruby library for fast reading Zip files.
|
130
|
+
summary: Openzip is a Ruby library (written in Rust) for fast reading Zip files.
|
128
131
|
test_files: []
|