capsium 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rake.yml +1 -4
- data/.github/workflows/release.yml +1 -2
- data/.rubocop.yml +10 -6
- data/Gemfile +0 -6
- data/capsium.gemspec +9 -8
- data/lib/capsium/cli.rb +29 -10
- data/lib/capsium/converters/jekyll.rb +63 -30
- data/lib/capsium/package/dataset.rb +35 -48
- data/lib/capsium/package/dataset_config.rb +28 -0
- data/lib/capsium/package/manifest.rb +21 -41
- data/lib/capsium/package/manifest_config.rb +19 -0
- data/lib/capsium/package/metadata.rb +13 -27
- data/lib/capsium/package/metadata_config.rb +17 -0
- data/lib/capsium/package/routes.rb +39 -97
- data/lib/capsium/package/routes_config.rb +74 -0
- data/lib/capsium/package/storage.rb +47 -22
- data/lib/capsium/package/storage_config.rb +9 -0
- data/lib/capsium/package.rb +18 -6
- data/lib/capsium/packager.rb +25 -63
- data/lib/capsium/protector.rb +15 -7
- data/lib/capsium/reactor.rb +52 -28
- data/lib/capsium/version.rb +1 -1
- metadata +73 -25
- data/images/005df7415a331c466ad2d9a42efdd212b6f42fe50b5fd3b3174c86c706f58244.png +0 -0
- data/images/0374025b3af99b8a473282c8cbbf9fcd29573cf41e586982f328f86c0690f43d.png +0 -0
- data/images/0bb4da785be40ef58e219470ebccb979325928b75453dc46bac23c6ee8a7a7cb.png +0 -0
- data/images/6aa294dccc81af594aacbe804e7ddffdc17eacc28357338108aea5d021d831ff.png +0 -0
- data/images/72dd3fbf3f4b475e27a0e7fb8137c475c32c41f8d222bcf62d6a9ccf102d9532.png +0 -0
- data/images/8772b6961d169738d7b0fa0b669b06fc2f40632d4c62586c7634fc17b93182a3.png +0 -0
- data/images/a998d842405933d45723606ff3f70162ec95b4ef30db25464a366184fd08fb9b.png +0 -0
- data/images/aa8980547e8c003d33273ab4d80e62da7f317bd7581b293c06d67f5331f24f31.png +0 -0
- data/images/bb78a872b539e0e9b2d80dee58acbb688f3f2727b324a5bf8bf417a69d94a166.png +0 -0
- data/images/c48fc83b17725d85fbb64d971196ebfccd8c5c757fe6aa5845303f6e315879b6.png +0 -0
- data/images/f08ef07308d08119ac2124bb7428c8bef17ef1ca70045696604d6e83015a9b91.png +0 -0
- data/images/f7514206111b695647eae9adfcf498ba3e0ff83ecfe25f3fc3ed8e9f04c5c726-1.png +0 -0
- data/images/f7514206111b695647eae9adfcf498ba3e0ff83ecfe25f3fc3ed8e9f04c5c726.png +0 -0
@@ -3,45 +3,31 @@
|
|
3
3
|
# lib/capsium/package/metadata.rb
|
4
4
|
require "shale"
|
5
5
|
require "forwardable"
|
6
|
+
require_relative "metadata_config"
|
6
7
|
|
7
8
|
module Capsium
|
8
9
|
class Package
|
9
|
-
class Dependency < Shale::Mapper
|
10
|
-
attribute :name, Shale::Type::String
|
11
|
-
attribute :version, Shale::Type::String
|
12
|
-
end
|
13
|
-
|
14
|
-
class MetadataData < Shale::Mapper
|
15
|
-
attribute :name, Shale::Type::String
|
16
|
-
attribute :version, Shale::Type::String
|
17
|
-
attribute :dependencies, Dependency, collection: true
|
18
|
-
end
|
19
|
-
|
20
10
|
class Metadata
|
21
|
-
attr_reader :path, :
|
11
|
+
attr_reader :path, :config
|
22
12
|
|
23
13
|
extend Forwardable
|
24
|
-
def_delegator :@
|
25
|
-
def_delegator :@
|
26
|
-
def_delegator :@
|
14
|
+
def_delegator :@config, :to_json
|
15
|
+
def_delegator :@config, :name
|
16
|
+
def_delegator :@config, :version
|
17
|
+
def_delegator :@config, :description # Delegate description method
|
18
|
+
def_delegator :@config, :dependencies
|
27
19
|
|
28
20
|
def initialize(path)
|
29
21
|
@path = path
|
30
|
-
@
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
def to_json(*_args)
|
38
|
-
@data.to_json
|
22
|
+
@config = if File.exist?(path)
|
23
|
+
MetadataData.from_json(File.read(path))
|
24
|
+
else
|
25
|
+
MetadataData.new
|
26
|
+
end
|
39
27
|
end
|
40
28
|
|
41
29
|
def save_to_file(output_path = @path)
|
42
|
-
File.
|
43
|
-
file.write(to_json)
|
44
|
-
end
|
30
|
+
File.write(output_path, to_json)
|
45
31
|
end
|
46
32
|
end
|
47
33
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "shale"
|
2
|
+
|
3
|
+
module Capsium
|
4
|
+
class Package
|
5
|
+
class Dependency < Shale::Mapper
|
6
|
+
attribute :name, Shale::Type::String
|
7
|
+
attribute :version, Shale::Type::String
|
8
|
+
end
|
9
|
+
|
10
|
+
class MetadataData < Shale::Mapper
|
11
|
+
attribute :name, Shale::Type::String
|
12
|
+
attribute :version, Shale::Type::String
|
13
|
+
attribute :description, Shale::Type::String # Add description attribute
|
14
|
+
attribute :dependencies, Dependency, collection: true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -3,154 +3,96 @@
|
|
3
3
|
# lib/capsium/package/routes.rb
|
4
4
|
require "json"
|
5
5
|
require "fileutils"
|
6
|
+
require_relative "routes_config"
|
6
7
|
|
7
8
|
module Capsium
|
8
9
|
class Package
|
9
|
-
class
|
10
|
-
|
11
|
-
|
12
|
-
def fs_path(manifest)
|
13
|
-
manifest.path_to_content_file(manifest.lookup(file).file)
|
14
|
-
end
|
15
|
-
|
16
|
-
def mime(manifest)
|
17
|
-
manifest.lookup(file).mime
|
18
|
-
end
|
19
|
-
|
20
|
-
def validate(manifest)
|
21
|
-
target_path = fs_path(manifest)
|
22
|
-
return if File.exist?(target_path)
|
23
|
-
|
24
|
-
raise "Route target does not exist: #{target_path}"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
class Route < Shale::Mapper
|
29
|
-
attribute :path, Shale::Type::String
|
30
|
-
attribute :target, RouteTarget
|
31
|
-
end
|
32
|
-
|
33
|
-
class RoutesData < Shale::Mapper
|
34
|
-
attribute :routes, Route, collection: true
|
35
|
-
|
36
|
-
def resolve(route)
|
37
|
-
routes.detect do |r|
|
38
|
-
r.path == route
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def add(route, target)
|
43
|
-
target = RouteTarget.new(file: target) if target.is_a?(String)
|
44
|
-
|
45
|
-
@routes << Route.new(path: route, target: target)
|
46
|
-
end
|
47
|
-
|
48
|
-
def update(route, updated_route, _updated_target)
|
49
|
-
r = @routes.resolve(route)
|
50
|
-
r.path = updated_route
|
51
|
-
r.target = target
|
52
|
-
r
|
53
|
-
end
|
10
|
+
class Routes
|
11
|
+
extend Forwardable
|
12
|
+
attr_reader :config
|
54
13
|
|
55
|
-
|
56
|
-
r = @routes.resolve(route)
|
57
|
-
@routes.remove(r)
|
58
|
-
end
|
14
|
+
def_delegators :@config, :to_json
|
59
15
|
|
60
|
-
|
61
|
-
@routes.sort_by!(&:path)
|
62
|
-
self
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
class Routes
|
67
|
-
attr_reader :path, :data, :index, :manifest
|
16
|
+
attr_reader :path, :config, :index, :manifest, :storage
|
68
17
|
|
69
18
|
ROUTES_FILE = "routes.json"
|
70
|
-
DEFAULT_INDEX_TARGET = "index.html"
|
19
|
+
DEFAULT_INDEX_TARGET = "content/index.html"
|
71
20
|
INDEX_ROUTE = "/"
|
72
21
|
|
73
|
-
def initialize(path, manifest)
|
22
|
+
def initialize(path, manifest, storage)
|
74
23
|
@path = path
|
75
24
|
@dir = File.dirname(path)
|
76
25
|
@manifest = manifest
|
77
|
-
@
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
26
|
+
@storage = storage
|
27
|
+
@config = if File.exist?(path)
|
28
|
+
RoutesConfig.from_json(File.read(path))
|
29
|
+
else
|
30
|
+
generate_routes
|
31
|
+
end
|
32
|
+
validate_index_path(@config.resolve(INDEX_ROUTE)&.target&.file)
|
83
33
|
validate
|
84
34
|
end
|
85
35
|
|
86
36
|
def resolve(url_path)
|
87
|
-
@
|
37
|
+
@config.resolve(url_path)
|
88
38
|
end
|
89
39
|
|
90
40
|
def add_route(route, target)
|
91
41
|
validate_route_target(route, target)
|
92
|
-
@
|
42
|
+
@config.add(route, target)
|
93
43
|
end
|
94
44
|
|
95
45
|
def update_route(route, updated_route, updated_target)
|
96
46
|
validate_route_target(updated_route, updated_target)
|
97
|
-
@
|
47
|
+
@config.update(route, updated_route, updated_target)
|
98
48
|
end
|
99
49
|
|
100
50
|
def remove_route(route)
|
101
|
-
@
|
51
|
+
@config.remove(route)
|
102
52
|
end
|
103
53
|
|
104
54
|
def validate
|
105
|
-
@
|
106
|
-
route.target.validate(@manifest)
|
55
|
+
@config.routes.each do |route|
|
56
|
+
route.target.validate(@manifest, @storage)
|
107
57
|
end
|
108
58
|
end
|
109
59
|
|
110
60
|
def to_json(*_args)
|
111
|
-
@
|
61
|
+
@config.sort!.to_json
|
112
62
|
end
|
113
63
|
|
114
64
|
def save_to_file(output_path = @path)
|
115
|
-
File.
|
116
|
-
file.write(to_json)
|
117
|
-
end
|
65
|
+
File.write(output_path, to_json)
|
118
66
|
end
|
119
67
|
|
120
68
|
private
|
121
69
|
|
122
|
-
def
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
content_path = @manifest.path_to_content_file(file_path).to_s
|
70
|
+
def generate_routes
|
71
|
+
r = RoutesConfig.new
|
72
|
+
manifest.config.sort!.content.each_with_object({}) do |data_item, _hash|
|
73
|
+
relative_path = data_item.file.sub(/^#{Package::CONTENT_DIR}/o, "")
|
74
|
+
r.add(relative_path, data_item.file)
|
128
75
|
|
129
|
-
|
130
|
-
|
76
|
+
# Ensure the index route is included
|
77
|
+
if File.basename(relative_path, ".*") == "index"
|
78
|
+
r.add("/index", data_item.file)
|
79
|
+
r.add("/", data_item.file)
|
131
80
|
end
|
132
|
-
|
133
|
-
routes.add("/#{clean_target_html_path(file_path)}", file_path) if file_path =~ /\.html$/
|
134
|
-
|
135
|
-
routes.add("/#{file_path}", file_path)
|
136
81
|
end
|
137
82
|
|
138
|
-
|
139
|
-
end
|
140
|
-
|
141
|
-
def clean_target_html_path(path)
|
142
|
-
File.dirname(path) + File.basename(path, ".html")
|
83
|
+
r
|
143
84
|
end
|
144
85
|
|
145
|
-
|
146
86
|
def validate_index_path(index_path)
|
147
|
-
|
87
|
+
return unless index_path
|
148
88
|
|
89
|
+
target_path = @manifest.path_to_content_file(index_path)
|
149
90
|
raise "Index file does not exist: #{target_path}" unless File.exist?(target_path)
|
91
|
+
raise "Index file is not an HTML file: #{target_path}" unless File.extname(target_path).downcase == ".html"
|
92
|
+
end
|
150
93
|
|
151
|
-
|
152
|
-
|
153
|
-
raise "Index file is not an HTML file: #{target_path}"
|
94
|
+
def validate_route_target(route, target)
|
95
|
+
# Add any necessary validation logic for the route and target
|
154
96
|
end
|
155
97
|
end
|
156
98
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "shale"
|
4
|
+
|
5
|
+
module Capsium
|
6
|
+
class Package
|
7
|
+
class RouteTarget < Shale::Mapper
|
8
|
+
attribute :file, Shale::Type::String
|
9
|
+
attribute :dataset, Shale::Type::String
|
10
|
+
|
11
|
+
def fs_path(manifest)
|
12
|
+
return unless file
|
13
|
+
|
14
|
+
manifest.path_to_content_file(manifest.lookup(file)&.file)
|
15
|
+
end
|
16
|
+
|
17
|
+
def mime(manifest)
|
18
|
+
manifest.lookup(file)&.mime
|
19
|
+
end
|
20
|
+
|
21
|
+
def validate(manifest, storage)
|
22
|
+
if file
|
23
|
+
target_path = fs_path(manifest)
|
24
|
+
unless target_path && File.exist?(target_path) && target_path.to_s.start_with?(manifest.content_path.to_s)
|
25
|
+
raise "Route target does not exist or is outside of the content directory: #{target_path}"
|
26
|
+
end
|
27
|
+
elsif dataset
|
28
|
+
unless storage.datasets.any? { |ds| ds.config.name == dataset }
|
29
|
+
raise "Dataset target does not exist: #{dataset}"
|
30
|
+
end
|
31
|
+
else
|
32
|
+
raise "Route target must have either a file or a dataset"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Route < Shale::Mapper
|
38
|
+
attribute :path, Shale::Type::String
|
39
|
+
attribute :target, RouteTarget
|
40
|
+
end
|
41
|
+
|
42
|
+
class RoutesConfig < Shale::Mapper
|
43
|
+
attribute :routes, Route, collection: true
|
44
|
+
|
45
|
+
def resolve(route)
|
46
|
+
routes.detect { |r| r.path == route }
|
47
|
+
end
|
48
|
+
|
49
|
+
def add(route, target)
|
50
|
+
target = RouteTarget.new(file: target) if target.is_a?(String)
|
51
|
+
r = Route.new(path: route, target: target)
|
52
|
+
@routes << r
|
53
|
+
r
|
54
|
+
end
|
55
|
+
|
56
|
+
def update(route, updated_route, updated_target)
|
57
|
+
r = resolve(route)
|
58
|
+
r.path = updated_route
|
59
|
+
r.target = updated_target
|
60
|
+
r
|
61
|
+
end
|
62
|
+
|
63
|
+
def remove(route)
|
64
|
+
r = resolve(route)
|
65
|
+
@routes.delete(r)
|
66
|
+
end
|
67
|
+
|
68
|
+
def sort!
|
69
|
+
@routes.sort_by!(&:path)
|
70
|
+
self
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -2,50 +2,75 @@
|
|
2
2
|
|
3
3
|
# lib/capsium/package/storage.rb
|
4
4
|
require "json"
|
5
|
+
require "shale"
|
6
|
+
require_relative "dataset"
|
7
|
+
require_relative "storage_config"
|
5
8
|
|
6
9
|
module Capsium
|
7
10
|
class Package
|
8
11
|
class Storage
|
9
|
-
|
12
|
+
extend Forwardable
|
13
|
+
attr_reader :config
|
14
|
+
|
15
|
+
def_delegators :@config, :to_json
|
10
16
|
|
11
|
-
|
17
|
+
attr_reader :datasets
|
12
18
|
|
13
19
|
def initialize(path)
|
14
20
|
@path = path
|
15
21
|
@dir = File.dirname(path)
|
16
22
|
@datasets_path = File.join(@dir, DATA_DIR)
|
23
|
+
@config = if File.exist?(path)
|
24
|
+
StorageConfig.from_json(File.read(path))
|
25
|
+
else
|
26
|
+
StorageConfig.new(datasets: generate_datasets)
|
27
|
+
end
|
17
28
|
@datasets = load_datasets || generate_datasets
|
18
29
|
end
|
19
30
|
|
20
31
|
def load_datasets
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
def as_json
|
28
|
-
{ datasets: datasets.map(&:as_json) }
|
29
|
-
end
|
30
|
-
|
31
|
-
def to_json(*_args)
|
32
|
-
JSON.pretty_generate(as_json)
|
32
|
+
if File.exist?(@path)
|
33
|
+
storage_data = StorageConfig.from_json(File.read(@path))
|
34
|
+
storage_data.datasets.map do |dataset_config|
|
35
|
+
dataset_config.to_dataset(@datasets_path)
|
36
|
+
end
|
37
|
+
end
|
33
38
|
end
|
34
39
|
|
35
40
|
def save_to_file(output_path = @path)
|
36
|
-
|
37
|
-
|
38
|
-
|
41
|
+
storage_config = StorageConfig.new(datasets: @datasets.map do |dataset|
|
42
|
+
DatasetConfig.from_dataset(dataset)
|
43
|
+
end)
|
44
|
+
File.write(output_path, storage_config.to_json)
|
39
45
|
end
|
40
46
|
|
41
47
|
def generate_datasets
|
42
|
-
datasets = []
|
43
48
|
paths = File.join(@datasets_path, "*.{yaml,yml,json,csv,tsv,sqlite,db}")
|
44
|
-
Dir.glob(paths).
|
45
|
-
|
46
|
-
|
49
|
+
Dir.glob(paths).map do |file_path|
|
50
|
+
Dataset.new(config: DatasetConfig.new(
|
51
|
+
name: File.basename(file_path,
|
52
|
+
".*"), source: file_path, format: detect_format(file_path)
|
53
|
+
))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def detect_format(file_path)
|
60
|
+
case File.extname(file_path).downcase
|
61
|
+
when ".yaml", ".yml"
|
62
|
+
"yaml"
|
63
|
+
when ".json"
|
64
|
+
"json"
|
65
|
+
when ".csv"
|
66
|
+
"csv"
|
67
|
+
when ".tsv"
|
68
|
+
"tsv"
|
69
|
+
when ".sqlite", ".db"
|
70
|
+
"sqlite"
|
71
|
+
else
|
72
|
+
raise "Unsupported data file type: #{File.extname(file_path)}"
|
47
73
|
end
|
48
|
-
datasets
|
49
74
|
end
|
50
75
|
end
|
51
76
|
end
|
data/lib/capsium/package.rb
CHANGED
@@ -16,7 +16,8 @@ require_relative "packager"
|
|
16
16
|
|
17
17
|
module Capsium
|
18
18
|
class Package
|
19
|
-
attr_reader :name, :path, :manifest, :metadata, :routes, :datasets,
|
19
|
+
attr_reader :name, :path, :manifest, :metadata, :routes, :datasets,
|
20
|
+
:storage, :load_type
|
20
21
|
|
21
22
|
MANIFEST_FILE = "manifest.json"
|
22
23
|
METADATA_FILE = "metadata.json"
|
@@ -28,9 +29,10 @@ module Capsium
|
|
28
29
|
DATA_DIR = "data"
|
29
30
|
ENCRYPTED_PACKAGING_FILE = "package.enc"
|
30
31
|
|
31
|
-
def initialize(path)
|
32
|
+
def initialize(path, load_type: nil)
|
32
33
|
@original_path = Pathname.new(path).expand_path
|
33
34
|
@path = prepare_package(@original_path)
|
35
|
+
@load_type = load_type || determine_load_type(path)
|
34
36
|
create_package_structure
|
35
37
|
load_package
|
36
38
|
@name = metadata.name
|
@@ -43,7 +45,6 @@ module Capsium
|
|
43
45
|
return decompress_cap_file(path) if File.extname(path) == ".cap"
|
44
46
|
|
45
47
|
raise "Error: The package must have a .cap extension"
|
46
|
-
|
47
48
|
end
|
48
49
|
|
49
50
|
raise "Invalid package path: #{path}"
|
@@ -70,7 +71,6 @@ module Capsium
|
|
70
71
|
metadata = Metadata.new(metadata_path)
|
71
72
|
package_name = metadata.name
|
72
73
|
package_version = metadata.version
|
73
|
-
package_dependencies = metadata.dependencies
|
74
74
|
|
75
75
|
package_path = File.join(temp_dir, "#{package_name}-#{package_version}")
|
76
76
|
FileUtils.mkdir_p(package_path)
|
@@ -92,9 +92,8 @@ module Capsium
|
|
92
92
|
|
93
93
|
# Optional
|
94
94
|
@manifest = Manifest.new(manifest_path)
|
95
|
-
@routes = Routes.new(routes_path, @manifest)
|
96
95
|
@storage = Storage.new(storage_path)
|
97
|
-
|
96
|
+
@routes = Routes.new(routes_path, @manifest, @storage)
|
98
97
|
end
|
99
98
|
|
100
99
|
def cleanup
|
@@ -107,6 +106,19 @@ module Capsium
|
|
107
106
|
@packager.package_files
|
108
107
|
end
|
109
108
|
|
109
|
+
def content_files
|
110
|
+
Dir.glob(File.join(content_path, "**", "*")).select do |file|
|
111
|
+
File.file?(file)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def determine_load_type(path)
|
116
|
+
return :directory if File.directory?(path)
|
117
|
+
return :cap_file if File.extname(path) == ".cap"
|
118
|
+
|
119
|
+
:unsaved
|
120
|
+
end
|
121
|
+
|
110
122
|
private
|
111
123
|
|
112
124
|
def create_package_structure
|
data/lib/capsium/packager.rb
CHANGED
@@ -11,28 +11,39 @@ module Capsium
|
|
11
11
|
class FileAlreadyExistsError < StandardError; end
|
12
12
|
|
13
13
|
def pack(package, options = {})
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
"Package target already exists, aborting: `#{relative_path_current(cap_file_path)}`"
|
24
|
-
end
|
25
|
-
|
14
|
+
directory = package.path
|
15
|
+
output_file_name = "#{package.metadata.name}-#{package.metadata.version}.cap"
|
16
|
+
output_directory = File.dirname(directory)
|
17
|
+
cap_file_path = File.join(output_directory, output_file_name)
|
18
|
+
|
19
|
+
if File.exist?(cap_file_path) && !options[:force]
|
20
|
+
raise FileAlreadyExistsError,
|
21
|
+
"Package target already exists, aborting: `#{relative_path_current(cap_file_path)}`"
|
22
|
+
elsif File.exist?(cap_file_path)
|
26
23
|
puts "Package target already exists, overwriting: `#{relative_path_current(cap_file_path)}`"
|
27
24
|
FileUtils.rm_f(cap_file_path)
|
28
25
|
end
|
29
26
|
|
30
27
|
Dir.mktmpdir do |dir|
|
31
|
-
FileUtils.cp_r("#{
|
28
|
+
FileUtils.cp_r("#{directory}/.", dir)
|
32
29
|
new_package = Package.new(dir)
|
33
30
|
new_package.solidify
|
34
|
-
|
31
|
+
new_cap_file_path = File.join(dir, output_file_name)
|
32
|
+
compress_package(new_package, new_cap_file_path)
|
33
|
+
puts "Package built at: #{new_cap_file_path}"
|
34
|
+
FileUtils.mv(new_cap_file_path, cap_file_path)
|
35
35
|
puts "Package created: #{relative_path_current(cap_file_path)}"
|
36
|
+
return cap_file_path
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def unpack(cap_file_path, destination)
|
41
|
+
Zip::File.open(cap_file_path) do |zip_file|
|
42
|
+
zip_file.each do |entry|
|
43
|
+
entry_path = File.join(destination, entry.name)
|
44
|
+
FileUtils.mkdir_p(File.dirname(entry_path))
|
45
|
+
entry.extract(entry_path)
|
46
|
+
end
|
36
47
|
end
|
37
48
|
end
|
38
49
|
|
@@ -44,55 +55,6 @@ module Capsium
|
|
44
55
|
end
|
45
56
|
end
|
46
57
|
|
47
|
-
# def package_files
|
48
|
-
# create_metadata_file
|
49
|
-
# create_manifest_file
|
50
|
-
# create_packaging_file
|
51
|
-
|
52
|
-
# compressor = Compressor.new(@package, @package.metadata[:compression])
|
53
|
-
# compressor.compress
|
54
|
-
|
55
|
-
# protector = Protector.new(@package, @package.metadata[:encryption], @package.metadata[:signature])
|
56
|
-
# protector.apply_encryption_and_sign
|
57
|
-
# end
|
58
|
-
|
59
|
-
# private
|
60
|
-
|
61
|
-
# def create_metadata_file
|
62
|
-
# metadata_path = File.join(@package.path, Package::METADATA_FILE)
|
63
|
-
# metadata_content = @package.metadata.to_h
|
64
|
-
# write_json_file(metadata_path, metadata_content)
|
65
|
-
# end
|
66
|
-
|
67
|
-
# def create_manifest_file
|
68
|
-
# manifest_path = File.join(@package.path, Package::MANIFEST_FILE)
|
69
|
-
# manifest_content = {
|
70
|
-
# files: Dir[File.join(@package.path, '**', '*')].reject { |f| File.directory?(f) }
|
71
|
-
# }
|
72
|
-
# write_json_file(manifest_path, manifest_content)
|
73
|
-
# end
|
74
|
-
|
75
|
-
def create_packaging_file
|
76
|
-
packaging_path = File.join(@package.path, Package::PACKAGING_FILE)
|
77
|
-
packaging_content = {
|
78
|
-
name: @package.name,
|
79
|
-
content_path: relative_path_package(@package.content_path),
|
80
|
-
data_path: relative_path_package(@package.data_path),
|
81
|
-
datasets: @package.datasets.map(&:to_h)
|
82
|
-
}
|
83
|
-
write_json_file(packaging_path, packaging_content)
|
84
|
-
end
|
85
|
-
|
86
|
-
def write_json_file(path, content)
|
87
|
-
File.open(path, "w") do |file|
|
88
|
-
file.write(JSON.pretty_generate(content))
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def relative_path_package(absolute_path)
|
93
|
-
Pathname.new(absolute_path).relative_path_from(Pathname.new(@package.path)).to_s
|
94
|
-
end
|
95
|
-
|
96
58
|
def relative_path_current(absolute_path)
|
97
59
|
Pathname.new(absolute_path).relative_path_from(Dir.pwd).to_s
|
98
60
|
end
|
data/lib/capsium/protector.rb
CHANGED
@@ -7,7 +7,8 @@ require "json"
|
|
7
7
|
|
8
8
|
module Capsium
|
9
9
|
class Protector
|
10
|
-
def initialize(package, encryption_metadata = nil,
|
10
|
+
def initialize(package, encryption_metadata = nil,
|
11
|
+
digital_signature_metadata = nil)
|
11
12
|
@package = package
|
12
13
|
@encryption_metadata = encryption_metadata
|
13
14
|
@digital_signature_metadata = digital_signature_metadata
|
@@ -32,7 +33,8 @@ module Capsium
|
|
32
33
|
|
33
34
|
def apply_encryption
|
34
35
|
encryption = @encryption_metadata
|
35
|
-
data = File.read(File.join(@package.path,
|
36
|
+
data = File.read(File.join(@package.path,
|
37
|
+
Package::ENCRYPTED_PACKAGING_FILE))
|
36
38
|
cipher = OpenSSL::Cipher.new(encryption[:algorithm])
|
37
39
|
cipher.encrypt
|
38
40
|
key = cipher.random_key
|
@@ -54,7 +56,8 @@ module Capsium
|
|
54
56
|
case key_management
|
55
57
|
when "secure"
|
56
58
|
# Implement secure key storage mechanism
|
57
|
-
File.write(File.join(@package.path, "encryption_key.secure"),
|
59
|
+
File.write(File.join(@package.path, "encryption_key.secure"),
|
60
|
+
Base64.encode64(key))
|
58
61
|
else
|
59
62
|
raise "Unknown key management strategy: #{key_management}"
|
60
63
|
end
|
@@ -69,7 +72,7 @@ module Capsium
|
|
69
72
|
signature_json = {
|
70
73
|
algorithm: @digital_signature_metadata[:algorithm],
|
71
74
|
certificateType: @digital_signature_metadata[:certificateType],
|
72
|
-
signature: Base64.encode64(signature_data)
|
75
|
+
signature: Base64.encode64(signature_data),
|
73
76
|
}
|
74
77
|
|
75
78
|
File.write(signature_file_path, JSON.pretty_generate(signature_json))
|
@@ -77,9 +80,14 @@ module Capsium
|
|
77
80
|
end
|
78
81
|
|
79
82
|
def combined_data(encrypted_file = nil)
|
80
|
-
metadata_content = File.read(File.join(@package.path,
|
81
|
-
|
82
|
-
|
83
|
+
metadata_content = File.read(File.join(@package.path,
|
84
|
+
Package::METADATA_FILE))
|
85
|
+
signature_content = File.read(signature_file_path).sub(
|
86
|
+
/"signature": ".*"/, '"signature": ""'
|
87
|
+
)
|
88
|
+
package_enc_content = File.read(encrypted_file || File.join(
|
89
|
+
@package.path, "#{@package.name}.enc"
|
90
|
+
))
|
83
91
|
|
84
92
|
metadata_content + signature_content + package_enc_content
|
85
93
|
end
|