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.
@@ -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
+ }
@@ -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
@@ -0,0 +1,10 @@
1
+ ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
2
+
3
+ require "mkmf"
4
+
5
+ File::unlink("Makefile") if (File::exist?("Makefile"))
6
+
7
+ pkg_config("libzip")
8
+
9
+ have_header('zip.h')
10
+ create_makefile('async_zip_ext')
@@ -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
+ }
@@ -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
@@ -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
+ }
@@ -0,0 +1,7 @@
1
+ #ifndef ASYNC_ZIP_WRITER_H
2
+ #define ASYNC_ZIP_WRITER_H
3
+
4
+ typedef void* (*archive_func_t)(void*);
5
+ void az_enqueue_task(archive_func_t func, void* data);
6
+
7
+ #endif
@@ -0,0 +1,5 @@
1
+ # Vips will print warnings to stdout unless this is set
2
+ ENV['IM_WARNING'] = "0"
3
+
4
+ require 'async_zip_ext'
5
+ require 'async_zip/version'
@@ -0,0 +1,3 @@
1
+ module AsyncZip
2
+ VERSION = "1.0.0"
3
+ end
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: []