openzip 0.1.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem](https://img.shields.io/gem/v/openzip.svg?style=flat-square)](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: []
|