capsium 0.1.1
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 +7 -0
- data/.github/workflows/rake.yml +18 -0
- data/.github/workflows/release.yml +24 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +8 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +12 -0
- data/README.adoc +258 -0
- data/Rakefile +12 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/capsium.gemspec +54 -0
- data/exe/capsium +6 -0
- 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
- data/lib/capsium/cli.rb +96 -0
- data/lib/capsium/converters/jekyll.rb +59 -0
- data/lib/capsium/package/dataset.rb +86 -0
- data/lib/capsium/package/manifest.rb +97 -0
- data/lib/capsium/package/metadata.rb +48 -0
- data/lib/capsium/package/routes.rb +157 -0
- data/lib/capsium/package/storage.rb +52 -0
- data/lib/capsium/package.rb +142 -0
- data/lib/capsium/packager.rb +100 -0
- data/lib/capsium/protector.rb +95 -0
- data/lib/capsium/reactor.rb +82 -0
- data/lib/capsium/thor_ext.rb +71 -0
- data/lib/capsium/version.rb +5 -0
- data/lib/capsium.rb +15 -0
- data/sig/capsium.rbs +4 -0
- metadata +354 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# lib/capsium/converters/jekyll_to_capsium.rb
|
4
|
+
require "fileutils"
|
5
|
+
require "json"
|
6
|
+
require "capsium/packager"
|
7
|
+
|
8
|
+
module Capsium
|
9
|
+
module Converters
|
10
|
+
class Jekyll
|
11
|
+
def initialize(site_directory, output_directory)
|
12
|
+
@site_directory = site_directory
|
13
|
+
@output_directory = output_directory
|
14
|
+
end
|
15
|
+
|
16
|
+
def convert
|
17
|
+
validate_site_directory
|
18
|
+
package_directory = prepare_package_directory
|
19
|
+
packager = Capsium::Packager.new(package_directory)
|
20
|
+
packager.pack
|
21
|
+
cleanup_package_directory(package_directory)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def validate_site_directory
|
27
|
+
return if Dir.exist?(@site_directory) && File.exist?(File.join(@site_directory, "index.html"))
|
28
|
+
|
29
|
+
raise "Invalid Jekyll site directory: #{@site_directory}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def prepare_package_directory
|
33
|
+
package_directory = File.join(@output_directory, "capsium_package")
|
34
|
+
FileUtils.mkdir_p(package_directory)
|
35
|
+
|
36
|
+
FileUtils.cp_r(Dir.glob("#{@site_directory}/*"), package_directory)
|
37
|
+
|
38
|
+
create_manifest(package_directory)
|
39
|
+
|
40
|
+
package_directory
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_manifest(package_directory)
|
44
|
+
manifest = {
|
45
|
+
"name" => "jekyll_site",
|
46
|
+
"version" => "1.0.0",
|
47
|
+
"description" => "A Jekyll site converted to a Capsium package",
|
48
|
+
"files" => Dir.glob("#{package_directory}/**/*").map { |file| file.sub("#{package_directory}/", "") }
|
49
|
+
}
|
50
|
+
|
51
|
+
File.write(File.join(package_directory, "manifest.json"), JSON.pretty_generate(manifest))
|
52
|
+
end
|
53
|
+
|
54
|
+
def cleanup_package_directory(package_directory)
|
55
|
+
FileUtils.rm_rf(package_directory)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# lib/capsium/package/dataset.rb
|
4
|
+
require "json"
|
5
|
+
require "yaml"
|
6
|
+
require "csv"
|
7
|
+
require "sqlite3"
|
8
|
+
|
9
|
+
module Capsium
|
10
|
+
class Package
|
11
|
+
class Dataset < Shale::Mapper
|
12
|
+
# {
|
13
|
+
# "datasets": [
|
14
|
+
# {
|
15
|
+
# "name": "animals",
|
16
|
+
# "source": "data/animals.yaml",
|
17
|
+
# "format": "yaml",
|
18
|
+
# "schema": "data/animals_schema.yaml"
|
19
|
+
# }
|
20
|
+
# ]
|
21
|
+
# }
|
22
|
+
attr_reader :name, :path, :type, :data
|
23
|
+
|
24
|
+
def initialize(path, data_path)
|
25
|
+
@path = path
|
26
|
+
@name = File.basename(@path, ".*")
|
27
|
+
@type = detect_type
|
28
|
+
@data_path = data_path
|
29
|
+
@data = load_data
|
30
|
+
end
|
31
|
+
|
32
|
+
def detect_type
|
33
|
+
case File.extname(@path).downcase
|
34
|
+
when /.ya?ml/ then :yaml
|
35
|
+
when ".json" then :json
|
36
|
+
when ".csv" then :csv
|
37
|
+
when ".tsv" then :tsv
|
38
|
+
when ".sqlite", ".db" then :sqlite
|
39
|
+
else
|
40
|
+
raise "Unsupported data file type: #{File.extname(@path)}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def load_data
|
45
|
+
case @type
|
46
|
+
when :yaml then YAML.load_file(@path)
|
47
|
+
when :json then JSON.parse(File.read(@path))
|
48
|
+
when :csv then CSV.read(@path, headers: true)
|
49
|
+
when :tsv then CSV.read(@path, col_sep: "\t", headers: true)
|
50
|
+
when :sqlite then load_sqlite_data
|
51
|
+
else
|
52
|
+
raise "Unsupported data file type: #{@type}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def as_json
|
57
|
+
{
|
58
|
+
name: name,
|
59
|
+
source: relative_path(path),
|
60
|
+
format: type.to_s
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_json(*_args)
|
65
|
+
JSON.pretty_generate(as_json)
|
66
|
+
end
|
67
|
+
|
68
|
+
def relative_path(path)
|
69
|
+
Pathname.new(path).relative_path_from(@data_path).to_s
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def load_sqlite_data
|
75
|
+
db = SQLite3::Database.new(@path)
|
76
|
+
tables = db.execute("SELECT name FROM sqlite_master WHERE type='table';")
|
77
|
+
data = {}
|
78
|
+
tables.each do |table|
|
79
|
+
table_name = table.first
|
80
|
+
data[table_name] = db.execute("SELECT * FROM #{table_name};")
|
81
|
+
end
|
82
|
+
data
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# lib/capsium/package/manifest.rb
|
4
|
+
require "json"
|
5
|
+
require "marcel"
|
6
|
+
require "shale"
|
7
|
+
|
8
|
+
module Capsium
|
9
|
+
class Package
|
10
|
+
class Manifest
|
11
|
+
attr_accessor :path, :content_path, :data
|
12
|
+
|
13
|
+
def initialize(path)
|
14
|
+
@path = path
|
15
|
+
# This is {package-name}/content
|
16
|
+
# or
|
17
|
+
# /tmp/../content
|
18
|
+
@content_path = File.join(File.dirname(@path), "content")
|
19
|
+
|
20
|
+
@data = if File.exist?(path)
|
21
|
+
ManifestData.from_json(File.read(path))
|
22
|
+
else
|
23
|
+
ManifestData.new(content: generate_manifest)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate_manifest
|
28
|
+
files = Dir[File.join(@content_path, "**", "*")].reject do |f|
|
29
|
+
File.directory?(f)
|
30
|
+
end
|
31
|
+
|
32
|
+
files.sort.map do |file_path|
|
33
|
+
ManifestDataItem.new(
|
34
|
+
file: relative_path(file_path),
|
35
|
+
mime: mime_from_path(file_path)
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def lookup(filename)
|
41
|
+
@data.content.detect do |data_item|
|
42
|
+
data_item.file == filename
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_json(*_args)
|
47
|
+
@data.to_json
|
48
|
+
end
|
49
|
+
|
50
|
+
def save_to_file(output_path = @path)
|
51
|
+
File.open(output_path, "w") do |file|
|
52
|
+
file.write(to_json)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def path_to_content_file(path)
|
57
|
+
Pathname.new(@content_path).join(path)
|
58
|
+
end
|
59
|
+
|
60
|
+
def content_file_exists?(path)
|
61
|
+
File.exist?(path_to_content_file(path))
|
62
|
+
end
|
63
|
+
|
64
|
+
def relative_path(path)
|
65
|
+
Pathname.new(path).relative_path_from(@content_path).to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def mime_from_path(path)
|
71
|
+
Marcel::MimeType.for(
|
72
|
+
Pathname.new(path),
|
73
|
+
name: File.basename(path),
|
74
|
+
extension: File.extname(path)
|
75
|
+
)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class ManifestDataItem < Shale::Mapper
|
80
|
+
attribute :file, Shale::Type::String
|
81
|
+
attribute :mime, Shale::Type::String
|
82
|
+
|
83
|
+
# json do
|
84
|
+
# map "file", to: :file
|
85
|
+
# map "mime", to: :mime
|
86
|
+
# end
|
87
|
+
end
|
88
|
+
|
89
|
+
class ManifestData < Shale::Mapper
|
90
|
+
attribute :content, ManifestDataItem, collection: true
|
91
|
+
|
92
|
+
# json do
|
93
|
+
# map "content", to: :content
|
94
|
+
# end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# lib/capsium/package/metadata.rb
|
4
|
+
require "shale"
|
5
|
+
require "forwardable"
|
6
|
+
|
7
|
+
module Capsium
|
8
|
+
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
|
+
class Metadata
|
21
|
+
attr_reader :path, :data
|
22
|
+
|
23
|
+
extend Forwardable
|
24
|
+
def_delegator :@data, :name
|
25
|
+
def_delegator :@data, :version
|
26
|
+
def_delegator :@data, :dependencies
|
27
|
+
|
28
|
+
def initialize(path)
|
29
|
+
@path = path
|
30
|
+
@data = if File.exist?(path)
|
31
|
+
MetadataData.from_json(File.read(path))
|
32
|
+
else
|
33
|
+
MetadataData.new
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_json(*_args)
|
38
|
+
@data.to_json
|
39
|
+
end
|
40
|
+
|
41
|
+
def save_to_file(output_path = @path)
|
42
|
+
File.open(output_path, "w") do |file|
|
43
|
+
file.write(to_json)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# lib/capsium/package/routes.rb
|
4
|
+
require "json"
|
5
|
+
require "fileutils"
|
6
|
+
|
7
|
+
module Capsium
|
8
|
+
class Package
|
9
|
+
class RouteTarget < Shale::Mapper
|
10
|
+
attribute :file, Shale::Type::String
|
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
|
54
|
+
|
55
|
+
def remove(route)
|
56
|
+
r = @routes.resolve(route)
|
57
|
+
@routes.remove(r)
|
58
|
+
end
|
59
|
+
|
60
|
+
def sort!
|
61
|
+
@routes.sort_by!(&:path)
|
62
|
+
self
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Routes
|
67
|
+
attr_reader :path, :data, :index, :manifest
|
68
|
+
|
69
|
+
ROUTES_FILE = "routes.json"
|
70
|
+
DEFAULT_INDEX_TARGET = "index.html"
|
71
|
+
INDEX_ROUTE = "/"
|
72
|
+
|
73
|
+
def initialize(path, manifest)
|
74
|
+
@path = path
|
75
|
+
@dir = File.dirname(path)
|
76
|
+
@manifest = manifest
|
77
|
+
@data = if File.exist?(path)
|
78
|
+
RoutesData.from_json(File.read(path))
|
79
|
+
else
|
80
|
+
generate_routes_from_manifest
|
81
|
+
end
|
82
|
+
validate_index_path(@data.resolve(INDEX_ROUTE).target.file)
|
83
|
+
validate
|
84
|
+
end
|
85
|
+
|
86
|
+
def resolve(url_path)
|
87
|
+
@data.resolve(url_path)
|
88
|
+
end
|
89
|
+
|
90
|
+
def add_route(route, target)
|
91
|
+
validate_route_target(route, target)
|
92
|
+
@data.add(route, target)
|
93
|
+
end
|
94
|
+
|
95
|
+
def update_route(route, updated_route, updated_target)
|
96
|
+
validate_route_target(updated_route, updated_target)
|
97
|
+
@data.update(route, updated_route, updated_target)
|
98
|
+
end
|
99
|
+
|
100
|
+
def remove_route(route)
|
101
|
+
@data._removed(route)
|
102
|
+
end
|
103
|
+
|
104
|
+
def validate
|
105
|
+
@data.routes.each do |route|
|
106
|
+
route.target.validate(@manifest)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def to_json(*_args)
|
111
|
+
@data.sort!.to_json
|
112
|
+
end
|
113
|
+
|
114
|
+
def save_to_file(output_path = @path)
|
115
|
+
File.open(output_path, "w") do |file|
|
116
|
+
file.write(to_json)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def generate_routes_from_manifest
|
123
|
+
routes = RoutesData.new
|
124
|
+
@manifest.data.content.each do |data_item|
|
125
|
+
file_path = data_item.file
|
126
|
+
# mime_type = data_item.mime
|
127
|
+
content_path = @manifest.path_to_content_file(file_path).to_s
|
128
|
+
|
129
|
+
if file_path == DEFAULT_INDEX_TARGET
|
130
|
+
routes.add(INDEX_ROUTE, DEFAULT_INDEX_TARGET)
|
131
|
+
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
|
+
end
|
137
|
+
|
138
|
+
routes
|
139
|
+
end
|
140
|
+
|
141
|
+
def clean_target_html_path(path)
|
142
|
+
File.dirname(path) + File.basename(path, ".html")
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
def validate_index_path(index_path)
|
147
|
+
target_path = @manifest.path_to_content_file(index_path)
|
148
|
+
|
149
|
+
raise "Index file does not exist: #{target_path}" unless File.exist?(target_path)
|
150
|
+
|
151
|
+
return if File.extname(target_path).downcase == ".html"
|
152
|
+
|
153
|
+
raise "Index file is not an HTML file: #{target_path}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# lib/capsium/package/storage.rb
|
4
|
+
require "json"
|
5
|
+
|
6
|
+
module Capsium
|
7
|
+
class Package
|
8
|
+
class Storage
|
9
|
+
attr_reader :datasets
|
10
|
+
|
11
|
+
DATA_DIR = "data"
|
12
|
+
|
13
|
+
def initialize(path)
|
14
|
+
@path = path
|
15
|
+
@dir = File.dirname(path)
|
16
|
+
@datasets_path = File.join(@dir, DATA_DIR)
|
17
|
+
@datasets = load_datasets || generate_datasets
|
18
|
+
end
|
19
|
+
|
20
|
+
def load_datasets
|
21
|
+
return unless File.exist?(@path)
|
22
|
+
|
23
|
+
storage_data = JSON.parse(File.read(@path))
|
24
|
+
@datasets = storage_data["storage"]
|
25
|
+
end
|
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)
|
33
|
+
end
|
34
|
+
|
35
|
+
def save_to_file(output_path = @path)
|
36
|
+
File.open(output_path, "w") do |file|
|
37
|
+
file.write(to_json)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def generate_datasets
|
42
|
+
datasets = []
|
43
|
+
paths = File.join(@datasets_path, "*.{yaml,yml,json,csv,tsv,sqlite,db}")
|
44
|
+
Dir.glob(paths).each do |file_path|
|
45
|
+
datasets << Dataset.new(file_path, @datasets_path)
|
46
|
+
# dataset_info[:table] = dataset.table_name if dataset.type == :sqlite
|
47
|
+
end
|
48
|
+
datasets
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# lib/capsium/package.rb
|
4
|
+
require "fileutils"
|
5
|
+
require "json"
|
6
|
+
require "yaml"
|
7
|
+
require "csv"
|
8
|
+
require "sqlite3"
|
9
|
+
require "zip"
|
10
|
+
require_relative "package/manifest"
|
11
|
+
require_relative "package/metadata"
|
12
|
+
require_relative "package/routes"
|
13
|
+
require_relative "package/dataset"
|
14
|
+
require_relative "package/storage"
|
15
|
+
require_relative "packager"
|
16
|
+
|
17
|
+
module Capsium
|
18
|
+
class Package
|
19
|
+
attr_reader :name, :path, :manifest, :metadata, :routes, :datasets, :storage
|
20
|
+
|
21
|
+
MANIFEST_FILE = "manifest.json"
|
22
|
+
METADATA_FILE = "metadata.json"
|
23
|
+
PACKAGING_FILE = "packaging.json"
|
24
|
+
SIGNATURE_FILE = "signature.json"
|
25
|
+
STORAGE_FILE = "storage.json"
|
26
|
+
ROUTES_FILE = "routes.json"
|
27
|
+
CONTENT_DIR = "content"
|
28
|
+
DATA_DIR = "data"
|
29
|
+
ENCRYPTED_PACKAGING_FILE = "package.enc"
|
30
|
+
|
31
|
+
def initialize(path)
|
32
|
+
@original_path = Pathname.new(path).expand_path
|
33
|
+
@path = prepare_package(@original_path)
|
34
|
+
create_package_structure
|
35
|
+
load_package
|
36
|
+
@name = metadata.name
|
37
|
+
end
|
38
|
+
|
39
|
+
def prepare_package(path)
|
40
|
+
return path if File.directory?(path)
|
41
|
+
|
42
|
+
if File.file?(path)
|
43
|
+
return decompress_cap_file(path) if File.extname(path) == ".cap"
|
44
|
+
|
45
|
+
raise "Error: The package must have a .cap extension"
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
raise "Invalid package path: #{path}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def solidify
|
53
|
+
@manifest.save_to_file
|
54
|
+
@metadata.save_to_file
|
55
|
+
@routes.save_to_file
|
56
|
+
@storage.save_to_file
|
57
|
+
end
|
58
|
+
|
59
|
+
def decompress_cap_file(file_path)
|
60
|
+
temp_dir = Dir.mktmpdir
|
61
|
+
metadata_path = File.join(temp_dir, METADATA_FILE)
|
62
|
+
|
63
|
+
# Extract metadata.json first
|
64
|
+
Zip::File.open(file_path) do |zip_file|
|
65
|
+
if entry = zip_file.find_entry(METADATA_FILE)
|
66
|
+
entry.extract(metadata_path)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
metadata = Metadata.new(metadata_path)
|
71
|
+
package_name = metadata.name
|
72
|
+
package_version = metadata.version
|
73
|
+
package_dependencies = metadata.dependencies
|
74
|
+
|
75
|
+
package_path = File.join(temp_dir, "#{package_name}-#{package_version}")
|
76
|
+
FileUtils.mkdir_p(package_path)
|
77
|
+
|
78
|
+
Zip::File.open(file_path) do |zip_file|
|
79
|
+
zip_file.each do |entry|
|
80
|
+
entry_path = File.join(package_path, entry.name)
|
81
|
+
FileUtils.mkdir_p(File.dirname(entry_path))
|
82
|
+
entry.extract(entry_path)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
package_path
|
87
|
+
end
|
88
|
+
|
89
|
+
def load_package
|
90
|
+
# Mandatory
|
91
|
+
@metadata = Metadata.new(metadata_path)
|
92
|
+
|
93
|
+
# Optional
|
94
|
+
@manifest = Manifest.new(manifest_path)
|
95
|
+
@routes = Routes.new(routes_path, @manifest)
|
96
|
+
@storage = Storage.new(storage_path)
|
97
|
+
# @datasets = load_datasets
|
98
|
+
end
|
99
|
+
|
100
|
+
def cleanup
|
101
|
+
return unless @path != @original_path && File.directory?(@path)
|
102
|
+
|
103
|
+
FileUtils.remove_entry(@path)
|
104
|
+
end
|
105
|
+
|
106
|
+
def package_files
|
107
|
+
@packager.package_files
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
def create_package_structure
|
113
|
+
FileUtils.mkdir_p(@path)
|
114
|
+
FileUtils.mkdir_p(content_path)
|
115
|
+
FileUtils.mkdir_p(data_path)
|
116
|
+
end
|
117
|
+
|
118
|
+
def content_path
|
119
|
+
File.join(@path, CONTENT_DIR)
|
120
|
+
end
|
121
|
+
|
122
|
+
def data_path
|
123
|
+
File.join(@path, DATA_DIR)
|
124
|
+
end
|
125
|
+
|
126
|
+
def routes_path
|
127
|
+
File.join(@path, ROUTES_FILE)
|
128
|
+
end
|
129
|
+
|
130
|
+
def storage_path
|
131
|
+
File.join(@path, STORAGE_FILE)
|
132
|
+
end
|
133
|
+
|
134
|
+
def metadata_path
|
135
|
+
File.join(@path, METADATA_FILE)
|
136
|
+
end
|
137
|
+
|
138
|
+
def manifest_path
|
139
|
+
File.join(@path, MANIFEST_FILE)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|