capsium 0.1.1 → 0.1.2
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/.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
|