async-ruby-zip 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.
- data/Gemfile.lock +31 -0
- data/README.md +30 -0
- data/async-ruby-zip.gemspec +77 -0
- data/ext/LICENSE +20 -0
- data/ext/archive.c +106 -0
- data/ext/archive.h +8 -0
- data/ext/archive_data.c +61 -0
- data/ext/archive_data.h +25 -0
- data/ext/archive_data_fwd.h +6 -0
- data/ext/async_zip.c +18 -0
- data/ext/async_zip.h +8 -0
- data/ext/callback.c +121 -0
- data/ext/callback.h +9 -0
- data/ext/carchive.c +219 -0
- data/ext/carchive.h +10 -0
- data/ext/carray.c +80 -0
- data/ext/carray.h +28 -0
- data/ext/cerror.c +74 -0
- data/ext/cerror.h +35 -0
- data/ext/cfilesystem.c +107 -0
- data/ext/cfilesystem.h +11 -0
- data/ext/extconf.rb +10 -0
- data/ext/task.c +62 -0
- data/ext/task.h +13 -0
- data/ext/writer.c +96 -0
- data/ext/writer.h +7 -0
- data/lib/async_zip.rb +5 -0
- data/lib/async_zip/version.rb +3 -0
- metadata +140 -0
data/ext/cfilesystem.c
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
#include "cfilesystem.h"
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <string.h>
|
5
|
+
#include <unistd.h>
|
6
|
+
#include <sys/stat.h>
|
7
|
+
#include <sys/types.h>
|
8
|
+
|
9
|
+
|
10
|
+
// Recursive directory creation
|
11
|
+
static void _mkdir(const char *dir, mode_t mode) {
|
12
|
+
|
13
|
+
char tmp[512];
|
14
|
+
char *p = NULL;
|
15
|
+
size_t len;
|
16
|
+
|
17
|
+
snprintf(tmp, sizeof(tmp),"%s",dir);
|
18
|
+
len = strlen(tmp);
|
19
|
+
if(tmp[len - 1] == '/')
|
20
|
+
tmp[len - 1] = 0;
|
21
|
+
for(p = tmp + 1; *p; p++)
|
22
|
+
if(*p == '/') {
|
23
|
+
*p = 0;
|
24
|
+
mkdir(tmp, mode);
|
25
|
+
*p = '/';
|
26
|
+
}
|
27
|
+
mkdir(tmp, S_IRWXU);
|
28
|
+
}
|
29
|
+
|
30
|
+
|
31
|
+
// Remove file or directory
|
32
|
+
void cfilesystem_remove(const char* filepath)
|
33
|
+
{
|
34
|
+
remove(filepath);
|
35
|
+
}
|
36
|
+
|
37
|
+
// Returns a positive value if path is found, otherwise 0
|
38
|
+
int cfilesystem_exists(const char* filepath)
|
39
|
+
{
|
40
|
+
return (access(filepath, F_OK) == 0 ? 1 : 0);
|
41
|
+
}
|
42
|
+
|
43
|
+
// Get the filename for the given file path
|
44
|
+
char* cfilesystem_filename(const char* filepath)
|
45
|
+
{
|
46
|
+
char* result = NULL;
|
47
|
+
char* last = strrchr(filepath, '/');
|
48
|
+
if(last)
|
49
|
+
{
|
50
|
+
result = strdup(last);
|
51
|
+
}
|
52
|
+
|
53
|
+
return result;
|
54
|
+
}
|
55
|
+
|
56
|
+
// Create directories
|
57
|
+
void cfilesystem_create_directories(const char* filepath)
|
58
|
+
{
|
59
|
+
_mkdir(filepath, S_IRWXU | S_IRWXG | S_IRWXO);
|
60
|
+
}
|
61
|
+
|
62
|
+
// Get a temporary filename.
|
63
|
+
char* cfilesystem_tempfilename()
|
64
|
+
{
|
65
|
+
char buffer[L_tmpnam];
|
66
|
+
tmpnam(buffer);
|
67
|
+
return strdup(buffer);
|
68
|
+
}
|
69
|
+
|
70
|
+
// Append one path to the other.
|
71
|
+
// Returns the combined path
|
72
|
+
char* cfilesystem_combine(const char* path1, const char* path2)
|
73
|
+
{
|
74
|
+
char* result = NULL;
|
75
|
+
|
76
|
+
if(!path1 && !path2) {
|
77
|
+
// no-op
|
78
|
+
}
|
79
|
+
else if(!path2 || !path2[0]) {
|
80
|
+
result = strdup(path1);
|
81
|
+
}
|
82
|
+
else if(!path1 || !path1[0]) {
|
83
|
+
result = strdup(path2);
|
84
|
+
}
|
85
|
+
else {
|
86
|
+
char* ptr;
|
87
|
+
size_t len1 = strlen(path1);
|
88
|
+
size_t len2 = strlen(path2);
|
89
|
+
|
90
|
+
size_t newlen = len1 + len2 + 1 + ((path1[len1 - 1] != '/' && path2[0] != '/') ? 1 : 0);
|
91
|
+
result = (char*)malloc(newlen);
|
92
|
+
ptr = result;
|
93
|
+
|
94
|
+
strcpy(ptr, path1);
|
95
|
+
ptr += len1;
|
96
|
+
|
97
|
+
if((ptr[-1] != '/') && (path2[0] != '/'))
|
98
|
+
{
|
99
|
+
ptr[0] = '/';
|
100
|
+
++ptr;
|
101
|
+
}
|
102
|
+
|
103
|
+
strcpy(ptr, path2);
|
104
|
+
}
|
105
|
+
|
106
|
+
return result;
|
107
|
+
}
|
data/ext/cfilesystem.h
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#ifndef EXTRA_CFILESYSTEM_H
|
2
|
+
#define EXTRA_CFILESYSTEM_H
|
3
|
+
|
4
|
+
void cfilesystem_remove(const char* filepath);
|
5
|
+
int cfilesystem_exists(const char* filepath);
|
6
|
+
char* cfilesystem_filename(const char* filepath);
|
7
|
+
void cfilesystem_create_directories(const char* filepath);
|
8
|
+
char* cfilesystem_tempfilename();
|
9
|
+
char* cfilesystem_combine(const char* path1, const char* path2);
|
10
|
+
|
11
|
+
#endif
|
data/ext/extconf.rb
ADDED
data/ext/task.c
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#include "task.h"
|
2
|
+
#include "carray.h"
|
3
|
+
|
4
|
+
VALUE cTask;
|
5
|
+
|
6
|
+
/* Get the source parameter */
|
7
|
+
static VALUE az_task_src(VALUE self)
|
8
|
+
{
|
9
|
+
return rb_iv_get(self, "@src");
|
10
|
+
}
|
11
|
+
|
12
|
+
/* Get the destination parameter */
|
13
|
+
static VALUE az_task_dst(VALUE self)
|
14
|
+
{
|
15
|
+
return rb_iv_get(self, "@dst");
|
16
|
+
}
|
17
|
+
|
18
|
+
/* Get the error parameter */
|
19
|
+
static VALUE az_task_error(VALUE self)
|
20
|
+
{
|
21
|
+
return rb_iv_get(self, "@error");
|
22
|
+
}
|
23
|
+
|
24
|
+
/* Get the files */
|
25
|
+
static VALUE az_task_files(VALUE self)
|
26
|
+
{
|
27
|
+
return rb_iv_get(self, "@files");
|
28
|
+
}
|
29
|
+
|
30
|
+
|
31
|
+
/* Initialize the object, called before the callback is invoked */
|
32
|
+
void az_task_init(VALUE self, const char* src_path, const char* dst_path, const char* err_str, const carray_str_t* files_arr)
|
33
|
+
{
|
34
|
+
rb_iv_set(self, "@src", (src_path ? rb_str_new2(src_path) : Qnil));
|
35
|
+
rb_iv_set(self, "@dst", (dst_path ? rb_str_new2(dst_path) : Qnil));
|
36
|
+
rb_iv_set(self, "@error", (err_str ? rb_str_new2(err_str) : Qnil));
|
37
|
+
|
38
|
+
// create an array
|
39
|
+
VALUE arr = rb_ary_new();
|
40
|
+
size_t len = carray_str_size(files_arr);
|
41
|
+
if(len > 0)
|
42
|
+
{
|
43
|
+
size_t i;
|
44
|
+
for(i = 0; i != len; ++i)
|
45
|
+
{
|
46
|
+
const char* s = carray_str_get(files_arr, i);
|
47
|
+
rb_ary_push(arr, rb_str_new2(s));
|
48
|
+
}
|
49
|
+
}
|
50
|
+
rb_iv_set(self, "@files", arr);
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
void init_async_zip_task()
|
55
|
+
{
|
56
|
+
cTask = rb_define_class_under(mAsyncZip, "Task", rb_cObject);
|
57
|
+
|
58
|
+
rb_define_method(cTask, "src", az_task_src, 0);
|
59
|
+
rb_define_method(cTask, "dst", az_task_dst, 0);
|
60
|
+
rb_define_method(cTask, "error", az_task_error, 0);
|
61
|
+
rb_define_method(cTask, "files", az_task_files, 0);
|
62
|
+
}
|
data/ext/task.h
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#ifndef ASYNC_ZIP_TASK_H
|
2
|
+
#define ASYNC_ZIP_TASK_H
|
3
|
+
|
4
|
+
#include "async_zip.h"
|
5
|
+
#include "carray.h"
|
6
|
+
|
7
|
+
extern VALUE cTask;
|
8
|
+
|
9
|
+
void az_task_init(VALUE self, const char* src_path, const char* dst_path, const char* err_str, const carray_str_t* files_arr);
|
10
|
+
|
11
|
+
void init_async_zip_task();
|
12
|
+
|
13
|
+
#endif
|
data/ext/writer.c
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
#include "writer.h"
|
2
|
+
#include "archive_data.h"
|
3
|
+
#include <memory.h>
|
4
|
+
#include <stdlib.h>
|
5
|
+
#include <pthread.h>
|
6
|
+
|
7
|
+
pthread_t az_writer_thread;
|
8
|
+
pthread_once_t qt_once = PTHREAD_ONCE_INIT;
|
9
|
+
|
10
|
+
typedef struct _az_write_task_t
|
11
|
+
{
|
12
|
+
archive_func_t func;
|
13
|
+
void* data;
|
14
|
+
struct _az_write_task_t* next;
|
15
|
+
} az_write_task_t;
|
16
|
+
|
17
|
+
|
18
|
+
/* Queue of tasks for processing. */
|
19
|
+
pthread_mutex_t az_writer_mutex = PTHREAD_MUTEX_INITIALIZER;
|
20
|
+
pthread_cond_t az_writer_cond = PTHREAD_COND_INITIALIZER;
|
21
|
+
az_write_task_t* az_writer_queue = NULL;
|
22
|
+
|
23
|
+
|
24
|
+
/* Push new task to front of the queue */
|
25
|
+
static void az_write_task_queue_push(az_write_task_t* wtask)
|
26
|
+
{
|
27
|
+
wtask->next = az_writer_queue;
|
28
|
+
az_writer_queue = wtask;
|
29
|
+
}
|
30
|
+
|
31
|
+
/* Pop next task from the queue; Returns NULL, when the queue is empty */
|
32
|
+
static az_write_task_t* az_write_task_queue_pop(void)
|
33
|
+
{
|
34
|
+
az_write_task_t* wtask = az_writer_queue;
|
35
|
+
if(wtask)
|
36
|
+
{
|
37
|
+
az_writer_queue = wtask->next;
|
38
|
+
}
|
39
|
+
|
40
|
+
return wtask;
|
41
|
+
}
|
42
|
+
|
43
|
+
|
44
|
+
/* Task processing queue */
|
45
|
+
static void* az_writer_thread_func(void* data)
|
46
|
+
{
|
47
|
+
int is_running = 1;
|
48
|
+
az_write_task_t* wtask = NULL;
|
49
|
+
|
50
|
+
while(is_running)
|
51
|
+
{
|
52
|
+
pthread_mutex_lock(&az_writer_mutex);
|
53
|
+
while (is_running && (wtask = az_write_task_queue_pop()) == NULL)
|
54
|
+
{
|
55
|
+
pthread_cond_wait(&az_writer_cond, &az_writer_mutex);
|
56
|
+
}
|
57
|
+
pthread_mutex_unlock(&az_writer_mutex);
|
58
|
+
|
59
|
+
if(wtask)
|
60
|
+
{
|
61
|
+
if(wtask->func)
|
62
|
+
{
|
63
|
+
wtask->func(wtask->data);
|
64
|
+
}
|
65
|
+
|
66
|
+
free(wtask);
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
return NULL;
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
/* Initialize the writer thread. The thread will wait for tasks to process */
|
75
|
+
static void az_init_writer_thread(void)
|
76
|
+
{
|
77
|
+
pthread_create(&az_writer_thread, NULL, az_writer_thread_func, NULL);
|
78
|
+
pthread_detach(az_writer_thread);
|
79
|
+
}
|
80
|
+
|
81
|
+
/* asynchronously invoke the func with the provided data */
|
82
|
+
void az_enqueue_task(archive_func_t func, void* data)
|
83
|
+
{
|
84
|
+
pthread_once(&qt_once, az_init_writer_thread);
|
85
|
+
|
86
|
+
pthread_mutex_lock(&az_writer_mutex);
|
87
|
+
|
88
|
+
az_write_task_t* wtask = (az_write_task_t*)malloc(sizeof(az_write_task_t));
|
89
|
+
memset(wtask, 0, sizeof(az_write_task_t));
|
90
|
+
wtask->func = func;
|
91
|
+
wtask->data = data;
|
92
|
+
az_write_task_queue_push(wtask);
|
93
|
+
|
94
|
+
pthread_mutex_unlock(&az_writer_mutex);
|
95
|
+
pthread_cond_signal(&az_writer_cond);
|
96
|
+
}
|
data/ext/writer.h
ADDED
data/lib/async_zip.rb
ADDED
metadata
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: async-ruby-zip
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Grigoriy Chudnov
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rdoc
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.12'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.12'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: jeweler
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.8.3
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.8.3
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Non-blocking zip reading and writing for Ruby.
|
79
|
+
email: g.chudnov@gmail.com
|
80
|
+
executables: []
|
81
|
+
extensions:
|
82
|
+
- ext/extconf.rb
|
83
|
+
extra_rdoc_files:
|
84
|
+
- README.md
|
85
|
+
files:
|
86
|
+
- Gemfile.lock
|
87
|
+
- README.md
|
88
|
+
- async-ruby-zip-1.0.0.gem
|
89
|
+
- async-ruby-zip.gemspec
|
90
|
+
- ext/LICENSE
|
91
|
+
- ext/archive.c
|
92
|
+
- ext/archive.h
|
93
|
+
- ext/archive_data.c
|
94
|
+
- ext/archive_data.h
|
95
|
+
- ext/archive_data_fwd.h
|
96
|
+
- ext/async_zip.c
|
97
|
+
- ext/async_zip.h
|
98
|
+
- ext/callback.c
|
99
|
+
- ext/callback.h
|
100
|
+
- ext/carchive.c
|
101
|
+
- ext/carchive.h
|
102
|
+
- ext/carray.c
|
103
|
+
- ext/carray.h
|
104
|
+
- ext/cerror.c
|
105
|
+
- ext/cerror.h
|
106
|
+
- ext/cfilesystem.c
|
107
|
+
- ext/cfilesystem.h
|
108
|
+
- ext/extconf.rb
|
109
|
+
- ext/task.c
|
110
|
+
- ext/task.h
|
111
|
+
- ext/writer.c
|
112
|
+
- ext/writer.h
|
113
|
+
- lib/async_zip.rb
|
114
|
+
- lib/async_zip/version.rb
|
115
|
+
homepage: https://github.com/gchudnov/async-ruby-zip
|
116
|
+
licenses:
|
117
|
+
- MIT
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ! '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
requirements: []
|
135
|
+
rubyforge_project:
|
136
|
+
rubygems_version: 1.8.24
|
137
|
+
signing_key:
|
138
|
+
specification_version: 3
|
139
|
+
summary: async-ruby-zip is a ruby extension that zip files asynchronously.
|
140
|
+
test_files: []
|