dgd-tools 0.1.5 → 0.1.10
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/.gitignore +2 -0
- data/Gemfile.lock +3 -1
- data/README.md +14 -0
- data/dgd-tools.gemspec +1 -0
- data/exe/dgd-manifest +74 -40
- data/exe/skotos-xml-diff +18 -7
- data/goods/chattheatre_kernellib.goods +12 -0
- data/lib/dgd-tools/manifest.rb +267 -98
- data/lib/dgd-tools/skotos_xml_obj.rb +129 -16
- data/lib/dgd-tools/version.rb +1 -1
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df6b6f5495201cda1059723bc87848c81ef6d112449fd147aed1a6c08873b13f
|
4
|
+
data.tar.gz: f5adb6e0b687e71002c25fdf694375b06b1c3e400a6a5adaa0f759ae502abea8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 91624cda3d356f2dc5d17e7a003a1ef21bf989c94ef5761e6c265d0fffc08fac932a59dd4e1da9f824e6f9cf79d9746eb9a33bff44a87d7693f9b34476852ecd
|
7
|
+
data.tar.gz: 2a3efbd628524723b1f7e15982dea8077088fd305a68cfd186a0a0396ac3f321c117e6d1301398b9b80c922524f479a4b6b97c8736b3116d9d7f7793f8fa38b1
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
dgd-tools (0.1.
|
4
|
+
dgd-tools (0.1.10)
|
5
5
|
nokogiri (~> 1.10.5)
|
6
|
+
optimist (~> 3.0.1)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
@@ -11,6 +12,7 @@ GEM
|
|
11
12
|
minitest (5.14.2)
|
12
13
|
nokogiri (1.10.10)
|
13
14
|
mini_portile2 (~> 2.4.0)
|
15
|
+
optimist (3.0.1)
|
14
16
|
rake (12.3.3)
|
15
17
|
|
16
18
|
PLATFORMS
|
data/README.md
CHANGED
@@ -14,6 +14,18 @@ DGD Manifest is a simple initial library system. I'm sure I'll figure more out a
|
|
14
14
|
|
15
15
|
This work has grown out of [SkotOS and ChatTheatre](https://github.com/ChatTheatre) tasks.
|
16
16
|
|
17
|
+
You can find example DGD manifest files under the "test" directory and also in [various](https://github.com/noahgibbs/prototype_vRWOT) [SkotOS-based games](https://github.com/ChatTheatre/gables_game) that use the DGD Manifest system.
|
18
|
+
|
19
|
+
You can find example "goods" (library) files under the "goods" subdirectory of this repo.
|
20
|
+
|
21
|
+
## WOE Objects and skotos-xml-diff
|
22
|
+
|
23
|
+
SkotOS-based games use an XML format for in-game objects called WOE, which is [documented in SkotOS-Doc](https://ChatTheatre.github.io/SkotOS-Doc). The skotos-xml-diff utility will diff between WOE objects or directories of WOE objects.
|
24
|
+
|
25
|
+
See SkotOS-Doc for more detail about how this can be used with a SkotOS game.
|
26
|
+
|
27
|
+
Run "skotos-xml-diff --help" for a list of options. You can tell it to ignore whitespace, to diff only the Merry (script) contents of the objects, and to ignore certain XML node types.
|
28
|
+
|
17
29
|
## Installation
|
18
30
|
|
19
31
|
You would normally install DGDTools directly: `gem install dgd-tools`.
|
@@ -26,6 +38,8 @@ If you have a DGD application that uses DGD Manifest, run `dgd-manifest install`
|
|
26
38
|
|
27
39
|
That fully-assembled DGD directory is named ".root". To run your dgd server, type "dgd-manifest server".
|
28
40
|
|
41
|
+
If you update files in your root and want to update files under the generated root directory, use "dgd-manifest update".
|
42
|
+
|
29
43
|
## Using DGD Manifest with your DGD Application
|
30
44
|
|
31
45
|
Your app will need a dgd.manifest file, which is a lot like NPM's package.json file.
|
data/dgd-tools.gemspec
CHANGED
data/exe/dgd-manifest
CHANGED
@@ -1,48 +1,82 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
require "optimist"
|
3
4
|
require "dgd-tools/manifest"
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
SUB_COMMANDS = %w(new test install update server)
|
7
|
+
|
8
|
+
OPTS = Optimist::options do
|
9
|
+
version "DGD-tools version #{DGD::VERSION}"
|
10
|
+
banner <<BANNER
|
11
|
+
Use dgd.manifest to assemble your DGD application.
|
12
|
+
|
13
|
+
Available subcommands:
|
14
|
+
new [project_name]: create a new DGD-manifest project
|
15
|
+
test: make sure the dgd.manifest file is well-formed and usable
|
16
|
+
install: compile the DGD application to a config file and a root directory
|
17
|
+
update: copy files into generated root directory but do *not* clear 'extra' files (e.g. user data)
|
18
|
+
server: run DGD with the generated root and configuration
|
8
19
|
|
9
|
-
|
10
|
-
|
11
|
-
|
20
|
+
Available options:
|
21
|
+
BANNER
|
22
|
+
opt :verbose, "Print verbose output where available"
|
23
|
+
stop_on SUB_COMMANDS
|
12
24
|
end
|
13
25
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
26
|
+
ARGV.push("install") if ARGV.size == 0
|
27
|
+
cmd = ARGV.shift
|
28
|
+
cmd_opts = case cmd
|
29
|
+
when "test"
|
30
|
+
#Optimist::options do
|
31
|
+
# opt :harsh, "check as exactly as possible"
|
32
|
+
#end
|
33
|
+
|
34
|
+
unless File.exist?("dgd.manifest")
|
35
|
+
raise "I don't see a dgd.manifest file in this directory!"
|
36
|
+
end
|
37
|
+
puts "Running dgd.manifest installer..."
|
38
|
+
repo = DGD::Manifest::Repo.new
|
39
|
+
repo.manifest_file("dgd.manifest")
|
40
|
+
repo.precheck(".", verbose: OPTS[:verbose])
|
41
|
+
puts "Verified Manifest packages: this looks likely correct."
|
42
|
+
|
43
|
+
when "install"
|
44
|
+
unless File.exist?("dgd.manifest")
|
45
|
+
raise "I don't see a dgd.manifest file in this directory!"
|
46
|
+
end
|
47
|
+
puts "Running DGD Manifest installer..."
|
48
|
+
repo = DGD::Manifest::Repo.new
|
49
|
+
repo.manifest_file("dgd.manifest")
|
50
|
+
current_dir = File.expand_path(".")
|
51
|
+
repo.precheck(current_dir, verbose: OPTS[:verbose])
|
52
|
+
repo.assemble_app(current_dir, verbose: OPTS[:verbose])
|
53
|
+
puts "Assembled DGD application into #{current_dir}"
|
54
|
+
|
55
|
+
when "update"
|
56
|
+
unless File.exist?("dgd.manifest")
|
57
|
+
raise "I don't see a dgd.manifest file in this directory!"
|
58
|
+
end
|
59
|
+
puts "Running DGD Manifest installer..."
|
60
|
+
repo = DGD::Manifest::Repo.new
|
61
|
+
repo.manifest_file("dgd.manifest")
|
62
|
+
current_dir = File.expand_path(".")
|
63
|
+
repo.precheck(current_dir, verbose: OPTS[:verbose])
|
64
|
+
repo.update_app(current_dir, verbose: OPTS[:verbose])
|
65
|
+
puts "Updated DGD application in #{current_dir}"
|
66
|
+
|
67
|
+
when "server"
|
68
|
+
puts "Starting DGD server..."
|
69
|
+
DGD::Manifest.system_call("~/.dgd-tools/dgd/bin/dgd dgd.config")
|
70
|
+
|
71
|
+
when "new"
|
72
|
+
unless ARGV.size == 1
|
73
|
+
puts "Usage: dgd-manifest new [project name]"
|
74
|
+
Optimist::die "Must supply exactly one argument to dgd-manifest new!"
|
75
|
+
end
|
76
|
+
appdir = DGD::Manifest::AppDirectory.new(File.expand_path ARGV[0])
|
77
|
+
appdir.name = ARGV[0]
|
78
|
+
appdir.create!
|
79
|
+
|
80
|
+
else
|
81
|
+
Optimist::die "Unknown subcommand: #{cmd.inspect}"
|
35
82
|
end
|
36
|
-
puts "Running DGD Manifest installer..."
|
37
|
-
repo = DGD::Manifest::Repo.new
|
38
|
-
repo.manifest_file("dgd.manifest")
|
39
|
-
current_dir = File.expand_path(".")
|
40
|
-
repo.precheck(current_dir)
|
41
|
-
repo.assemble_app(current_dir)
|
42
|
-
puts "Assembled DGD application into #{current_dir}"
|
43
|
-
when "server"
|
44
|
-
puts "Starting DGD server..."
|
45
|
-
DGD::Manifest.system_call("~/.dgd-tools/dgd/bin/dgd dgd.config")
|
46
|
-
else
|
47
|
-
raise "Unrecognised #{$0} command: #{ARGV[0].inspect}!"
|
48
|
-
end
|
data/exe/skotos-xml-diff
CHANGED
@@ -4,17 +4,28 @@
|
|
4
4
|
# SkotOS-or-similar game to find out what updates should
|
5
5
|
# be merged between them.
|
6
6
|
|
7
|
+
require 'optimist'
|
7
8
|
require "dgd-tools/skotos_xml_obj"
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
OPTS = Optimist::options do
|
11
|
+
version "DGD-tools version #{DGD::VERSION}"
|
12
|
+
banner <<BANNER
|
13
|
+
Usage:
|
14
|
+
skotos-xml-diff [options] <file_or_dir_1> <file_or_dir_2>
|
15
|
+
where [options] are:
|
16
|
+
BANNER
|
17
|
+
opt :version, "Print DGD version and exit"
|
18
|
+
opt :merry_only, "Only diff Merry scripts"
|
19
|
+
opt :ignore_whitespace, "Ignore whitespace in final diff"
|
20
|
+
opt :ignore_types, "Comma-separated list of XML node types to ignore (e.g. Combat:Base,Base:Exit)", type: :string
|
12
21
|
end
|
13
22
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
23
|
+
Optimist::die "Supply exactly two files or directories -- you supplied #{ARGV.size}!" unless ARGV.size == 2
|
24
|
+
Optimist::die "Supply both files or both directories, not one of each!" if File.directory?(ARGV[0]) ^ File.directory?(ARGV[1])
|
25
|
+
|
26
|
+
SkotOS::XMLObject.merry_only = true if OPTS[:merry_only]
|
27
|
+
SkotOS::XMLObject.ignore_whitespace = true if OPTS[:ignore_whitespace]
|
28
|
+
SkotOS::XMLObject.ignore_types = OPTS[:ignore_types].split(",") if OPTS[:ignore_types]
|
18
29
|
|
19
30
|
if File.directory?(ARGV[0])
|
20
31
|
diff = SkotOS::XMLObject.diff_dirs(*ARGV)
|
data/lib/dgd-tools/manifest.rb
CHANGED
@@ -16,38 +16,39 @@ module DGD::Manifest
|
|
16
16
|
}
|
17
17
|
KERNEL_PATHS = KERNEL_PATH_MAP.values
|
18
18
|
DEFAULT_KERNELLIB_URL = "https://github.com/ChatTheatre/kernellib"
|
19
|
-
|
20
19
|
GENERATED_ROOT = ".root"
|
21
20
|
|
22
21
|
def self.system_call(cmd)
|
23
22
|
puts "Running command: #{cmd.inspect}..."
|
24
23
|
system(cmd, out: $stdout, err: :out)
|
25
24
|
unless $?.success?
|
26
|
-
raise "Error running command: #{cmd.inspect}!"
|
25
|
+
raise "Error running command in #{Dir.pwd}: #{cmd.inspect}!"
|
27
26
|
end
|
28
27
|
end
|
29
28
|
|
30
29
|
# This is a repo of everything DGD Manifest saves between runs.
|
31
30
|
# It includes downloaded Git repos, Goods files and more.
|
32
31
|
class Repo
|
33
|
-
attr_reader :
|
32
|
+
attr_reader :shared_dir
|
34
33
|
|
35
34
|
def initialize
|
35
|
+
@no_manifest_file = true
|
36
36
|
@home = ENV["HOME"]
|
37
|
-
@
|
38
|
-
Dir.mkdir(@
|
37
|
+
@shared_dir = "#{@home}/.dgd-tools"
|
38
|
+
Dir.mkdir(@shared_dir) unless File.directory?(@shared_dir)
|
39
|
+
|
39
40
|
["git", "goods"].each do |subdir|
|
40
|
-
full_subdir = "#{@
|
41
|
+
full_subdir = "#{@shared_dir}/#{subdir}"
|
41
42
|
Dir.mkdir(full_subdir) unless File.directory?(full_subdir)
|
42
43
|
end
|
43
44
|
|
44
|
-
unless File.exist?("#{@
|
45
|
-
dgd_dir = "#{@
|
45
|
+
unless File.exist?("#{@shared_dir}/dgd/bin/dgd")
|
46
|
+
dgd_dir = "#{@shared_dir}/dgd"
|
46
47
|
if File.directory?(dgd_dir)
|
47
48
|
# Not clear to me what to do here...
|
48
49
|
else
|
49
50
|
DGD::Manifest.system_call("git clone https://github.com/ChatTheatre/dgd.git #{dgd_dir}")
|
50
|
-
Dir.chdir("#{@
|
51
|
+
Dir.chdir("#{@shared_dir}/dgd/src") do
|
51
52
|
DGD::Manifest.system_call(DGD_BUILD_COMMAND)
|
52
53
|
end
|
53
54
|
end
|
@@ -60,82 +61,120 @@ module DGD::Manifest
|
|
60
61
|
end
|
61
62
|
|
62
63
|
def manifest_file(path)
|
63
|
-
raise "Already have a dgd.manifest file!"
|
64
|
+
raise "Already have a dgd.manifest file!" unless @no_manifest_file
|
64
65
|
|
65
|
-
@
|
66
|
+
@no_manifest_file = false
|
67
|
+
@manifest_file ||= AppFile.new(self, path, shared_dir: shared_dir)
|
66
68
|
end
|
67
69
|
|
68
|
-
|
69
|
-
|
70
|
+
protected
|
71
|
+
|
72
|
+
# This includes files to assemble... But also subdirectories and commands. This format is
|
73
|
+
# unstable and ugly, and should not be exposed to outside parties who might later depend on it.
|
74
|
+
def assembly_operations(location, verbose:)
|
75
|
+
operations = []
|
70
76
|
|
71
|
-
|
72
|
-
|
73
|
-
|
77
|
+
raise("No manifest file!") if @no_manifest_file
|
78
|
+
|
79
|
+
# For each spec, put its dependencies before itself in order
|
80
|
+
@manifest_file.ordered_specs.each do |spec|
|
81
|
+
spec_git_repo = spec.source
|
82
|
+
spec_git_repo.use_details(spec.source_details) # This sets things like checked-out branch
|
74
83
|
|
75
84
|
spec.paths.each do |from, to|
|
76
|
-
|
85
|
+
# Note: spec_git_repo.local_dir is an absolute path.
|
86
|
+
from_path = "#{spec_git_repo.local_dir}/#{from}"
|
77
87
|
if File.directory?(from_path)
|
78
88
|
files = Dir["#{from_path}/**/*"].to_a + Dir["#{from_path}/**/.*"].to_a
|
79
89
|
dirs = files.select { |file| File.directory?(file) }
|
80
90
|
non_dirs = files - dirs
|
81
|
-
|
91
|
+
operations << { cmd: "cp", from: from_path, to: to, dirs: dirs, non_dirs: non_dirs, comment: :single_dir }
|
82
92
|
elsif from_path["*"] # If from_path contains at least one asterisk
|
83
93
|
components = from.split("/")
|
84
94
|
first_wild_idx = components.index { |item| item["*"] }
|
85
95
|
no_wild_from_path = components[0..(first_wild_idx-1)].join("/")
|
86
96
|
wild_path = components[first_wild_idx..-1].join("/")
|
87
97
|
|
88
|
-
files = Dir["#{
|
98
|
+
files = Dir["#{spec_git_repo.local_dir}/#{no_wild_from_path}/#{wild_path}"].to_a
|
89
99
|
dirs = files.select { |file| File.directory?(file) }
|
90
100
|
dirs += files.map { |f| File.dirname(f) }
|
91
101
|
dirs.uniq!
|
92
102
|
|
93
103
|
non_dirs = files - dirs
|
94
|
-
|
104
|
+
operations << { cmd: "cp", from: "#{spec_git_repo.local_dir}/#{no_wild_from_path}", to: to, dirs: dirs, non_dirs: non_dirs, comment: :path_wildcard }
|
95
105
|
else
|
96
106
|
# A single file
|
97
|
-
|
107
|
+
operations << { cmd: "cp", from: from_path, to: to, dirs: [], non_dirs: [from_path], comment: :single_file }
|
98
108
|
end
|
99
109
|
end
|
100
110
|
end
|
101
111
|
|
102
|
-
|
112
|
+
app_path = "#{File.expand_path(location)}/#{@manifest_file.app_root}"
|
113
|
+
app_files = Dir["#{app_path}/**/*"].to_a
|
114
|
+
app_dirs = app_files.select { |f| File.directory?(f) }
|
115
|
+
app_non_dirs = app_files - app_dirs
|
116
|
+
unless app_dirs.empty? && app_non_dirs.empty?
|
117
|
+
operations << { cmd: "cp", from: app_path, to: ".", dirs: app_dirs, non_dirs: app_non_dirs, comment: :app_files } # No source
|
118
|
+
end
|
119
|
+
|
120
|
+
operations
|
103
121
|
end
|
104
122
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
123
|
+
public
|
124
|
+
|
125
|
+
def dgd_root(location)
|
126
|
+
"#{File.expand_path(location)}/#{GENERATED_ROOT}"
|
127
|
+
end
|
110
128
|
|
111
|
-
|
112
|
-
|
129
|
+
def assemble_app(location, verbose:)
|
130
|
+
Dir[File.join(dgd_root(location), "*")].each { |dir| FileUtils.rm_rf dir }
|
113
131
|
|
114
|
-
|
115
|
-
|
132
|
+
write_app_files(location, verbose: verbose)
|
133
|
+
end
|
116
134
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
135
|
+
def update_app(location, verbose:)
|
136
|
+
write_app_files(location, verbose: verbose)
|
137
|
+
end
|
138
|
+
|
139
|
+
protected
|
140
|
+
|
141
|
+
def write_app_files(location, verbose:)
|
142
|
+
Dir.chdir(location) do
|
143
|
+
write_config_file("#{location}/dgd.config")
|
144
|
+
FileUtils.mkdir_p("#{location}/state") # Statedir for statedumps, editor files, etc.
|
145
|
+
|
146
|
+
assembly_operations(location, verbose: verbose).each do |sd_hash|
|
147
|
+
to_path = "#{dgd_root(location)}/#{sd_hash[:to]}"
|
148
|
+
|
149
|
+
if verbose
|
150
|
+
puts " Copy #{sd_hash[:from]} -> #{sd_hash[:to]}, files #{sd_hash[:non_dirs].join(", ")}"
|
151
|
+
end
|
121
152
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
153
|
+
# Make appropriate dirs, including empty ones
|
154
|
+
sd_hash[:dirs].each do |dir|
|
155
|
+
FileUtils.mkdir_p dir.sub(sd_hash[:from], to_path)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Copy all files
|
159
|
+
sd_hash[:non_dirs].each do |from_file|
|
160
|
+
to_file = from_file.sub(sd_hash[:from], "#{dgd_root(location)}/#{sd_hash[:to]}")
|
161
|
+
to_dir = File.dirname(to_file)
|
162
|
+
begin
|
163
|
+
FileUtils.mkdir_p to_dir
|
164
|
+
FileUtils.cp from_file, to_file
|
165
|
+
rescue
|
166
|
+
puts "Error when copying: #{from_file} -> #{to_file} in #{sd_hash.inspect}"
|
167
|
+
raise
|
168
|
+
end
|
169
|
+
end
|
128
170
|
end
|
129
171
|
end
|
130
172
|
end
|
131
173
|
|
132
|
-
|
133
|
-
app_path = "#{File.expand_path(location)}/#{@manifest_file.app_root}"
|
134
|
-
app_files = Dir["#{app_path}/**"].to_a.select { |f| !File.directory?(f) }
|
174
|
+
public
|
135
175
|
|
136
|
-
|
137
|
-
all_files =
|
138
|
-
all_files.sort!
|
176
|
+
def precheck(location, verbose:)
|
177
|
+
all_files = assembly_operations(location, verbose: verbose).flat_map { |sd| sd[:non_dirs] }
|
139
178
|
|
140
179
|
if all_files.size != all_files.uniq.size
|
141
180
|
repeated = all_files.uniq.select { |f| all_files.count(f) > 1 }
|
@@ -145,40 +184,7 @@ module DGD::Manifest
|
|
145
184
|
|
146
185
|
def write_config_file(path)
|
147
186
|
File.open(path, "wb") do |f|
|
148
|
-
f.write
|
149
|
-
/* These are SkotOS limits. They are enormous. They should
|
150
|
-
be configurable but they are not yet. */
|
151
|
-
telnet_port = ([
|
152
|
-
"*":50100 /* telnet port number */
|
153
|
-
]);
|
154
|
-
binary_port = ([
|
155
|
-
"*":50110 /* Failsafe */
|
156
|
-
]); /* binary ports */
|
157
|
-
directory = "./#{GENERATED_ROOT}";
|
158
|
-
|
159
|
-
users = 100; /* max # of users */
|
160
|
-
editors = 40; /* max # of editor sessions */
|
161
|
-
ed_tmpfile = "../state/ed"; /* proto editor tmpfile */
|
162
|
-
swap_file = "../state/swap"; /* swap file */
|
163
|
-
swap_size = 1048576; /* # sectors in swap file */
|
164
|
-
sector_size = 512; /* swap sector size */
|
165
|
-
swap_fragment = 4096; /* fragment to swap out */
|
166
|
-
static_chunk = 64512; /* static memory chunk */
|
167
|
-
dynamic_chunk = 261120; /* dynamic memory chunk */
|
168
|
-
dump_file = "../state/dump"; /* dump file */
|
169
|
-
dump_interval = 3600; /* dump interval */
|
170
|
-
|
171
|
-
typechecking = 2; /* highest level of typechecking */
|
172
|
-
include_file = "/include/std.h"; /* standard include file */
|
173
|
-
include_dirs = ({ "/include", "~/include" }); /* directories to search */
|
174
|
-
auto_object = "/kernel/lib/auto"; /* auto inherited object */
|
175
|
-
driver_object = "/kernel/sys/driver"; /* driver object */
|
176
|
-
create = "_F_create"; /* name of create function */
|
177
|
-
|
178
|
-
array_size = 16384; /* max array size */
|
179
|
-
objects = 262144; /* max # of objects */
|
180
|
-
call_outs = 16384; /* max # of call_outs */
|
181
|
-
CONTENTS
|
187
|
+
f.write @manifest_file.dgd_config.as_file
|
182
188
|
end
|
183
189
|
end
|
184
190
|
end
|
@@ -192,8 +198,8 @@ CONTENTS
|
|
192
198
|
def initialize(repo, git_url)
|
193
199
|
@git_url = git_url
|
194
200
|
@repo = repo
|
195
|
-
local_path = git_url.tr("/\\", "_")
|
196
|
-
@local_dir = "#{@repo.
|
201
|
+
local_path = git_url.tr("/\\ ", "_")
|
202
|
+
@local_dir = "#{@repo.shared_dir}/git/#{local_path}"
|
197
203
|
|
198
204
|
if File.directory?(@local_dir)
|
199
205
|
Dir.chdir(@local_dir) do
|
@@ -205,40 +211,39 @@ CONTENTS
|
|
205
211
|
end
|
206
212
|
|
207
213
|
def default_branch
|
208
|
-
|
209
|
-
output = `git rev-parse --abbrev-ref origin/HEAD`.chomp
|
210
|
-
@default_branch = output.gsub(/^origin\//, "")
|
214
|
+
@default_branch ||= `git rev-parse --abbrev-ref origin/HEAD`.chomp.gsub(/^origin\//, "")
|
211
215
|
end
|
212
216
|
|
213
217
|
def use_details(details)
|
214
218
|
if details["branch"]
|
215
219
|
Dir.chdir(@local_dir) do
|
216
|
-
DGD::Manifest.system_call("git checkout #{details["branch"]}")
|
220
|
+
DGD::Manifest.system_call("git checkout #{details["branch"]} && git pull")
|
217
221
|
end
|
218
222
|
else
|
219
223
|
Dir.chdir(@local_dir) do
|
220
|
-
DGD::Manifest.system_call("git checkout #{default_branch}")
|
224
|
+
DGD::Manifest.system_call("git checkout #{default_branch} && git pull")
|
221
225
|
end
|
222
226
|
end
|
223
227
|
end
|
224
228
|
end
|
225
229
|
|
230
|
+
# This class parses the DGD manifest
|
226
231
|
class AppFile
|
227
232
|
attr_reader :path
|
228
233
|
attr_reader :repo
|
229
234
|
attr_reader :specs
|
230
|
-
attr_reader :
|
235
|
+
attr_reader :dgd_config
|
236
|
+
attr_reader :shared_dir
|
231
237
|
|
232
|
-
def initialize(repo, path)
|
238
|
+
def initialize(repo, path, shared_dir:)
|
233
239
|
@path = path
|
234
240
|
@repo = repo
|
241
|
+
@shared_dir = shared_dir
|
235
242
|
raise("No such dgd.manifest file as #{path.inspect}!") unless File.exist?(path)
|
236
243
|
contents = AppFile.parse_manifest_file(path)
|
237
244
|
|
238
245
|
read_manifest_file(contents)
|
239
246
|
|
240
|
-
@app_root = contents["app_root"] || "app"
|
241
|
-
|
242
247
|
output_paths = @specs.flat_map { |s| s.paths.values }
|
243
248
|
unless output_paths == output_paths.uniq
|
244
249
|
repeated_paths = output_paths.select { |p| output_paths.count(p) > 1 }
|
@@ -254,9 +259,9 @@ CONTENTS
|
|
254
259
|
#else
|
255
260
|
# puts "This dgd.manifest needs the default Kernel Library."
|
256
261
|
# # This app has specified no kernellib paths -- add them
|
257
|
-
#
|
262
|
+
# spec_git_repo = @repo.git_repo(DEFAULT_KERNELLIB_URL)
|
258
263
|
# klib_spec = GoodsSpec.new @repo, name: "default Kernel Library",
|
259
|
-
# source:
|
264
|
+
# source: spec_git_repo, paths: KERNEL_PATH_MAP
|
260
265
|
# specs.unshift klib_spec
|
261
266
|
#end
|
262
267
|
|
@@ -285,6 +290,12 @@ CONTENTS
|
|
285
290
|
|
286
291
|
@specs = []
|
287
292
|
|
293
|
+
@dgd_config = DGDRuntimeConfig.new (contents["config"] || {})
|
294
|
+
|
295
|
+
if contents["app_root"]
|
296
|
+
raise "App_root must now be inside config block!"
|
297
|
+
end
|
298
|
+
|
288
299
|
if contents["unbundled_goods"]
|
289
300
|
raise "Unbundled_goods must be an array!" unless contents["unbundled_goods"].is_a?(Array)
|
290
301
|
|
@@ -296,7 +307,10 @@ CONTENTS
|
|
296
307
|
|
297
308
|
@specs += contents["goods"].map do |goods_url|
|
298
309
|
begin
|
299
|
-
|
310
|
+
text_contents = URI.open(goods_url).read
|
311
|
+
local_path = shared_dir + "/goods/" + goods_url.tr("/\\ ", "_")
|
312
|
+
File.open(local_path, "wb") { |f| f.write(text_contents) }
|
313
|
+
json_contents = JSON.parse text_contents
|
300
314
|
rescue
|
301
315
|
STDERR.puts "Error reading or parsing by URL: #{goods_url.inspect}"
|
302
316
|
raise
|
@@ -306,9 +320,15 @@ CONTENTS
|
|
306
320
|
end
|
307
321
|
end
|
308
322
|
|
323
|
+
def app_root
|
324
|
+
@dgd_config.app_root
|
325
|
+
end
|
326
|
+
|
309
327
|
def unbundled_json_to_spec(fields)
|
310
328
|
source = nil
|
311
329
|
source_details = nil
|
330
|
+
dependencies = []
|
331
|
+
|
312
332
|
if fields["git"]
|
313
333
|
raise "A git source requires a git url: #{fields.inspect}!" unless fields["git"]["url"]
|
314
334
|
source = @repo.git_repo(fields["git"]["url"])
|
@@ -321,9 +341,46 @@ CONTENTS
|
|
321
341
|
raise "Paths in Goods files must map strings to strings! #{fields["paths"].inspect}"
|
322
342
|
end
|
323
343
|
|
324
|
-
|
344
|
+
if fields["dependencies"]
|
345
|
+
# For now, permit a single string as a dependency.
|
346
|
+
fields["dependencies"] = [ fields["dependencies"] ] if fields["dependencies"].is_a?(String)
|
347
|
+
|
348
|
+
goods_url = nil
|
349
|
+
fields["dependencies"].each do |dep|
|
350
|
+
if dep.is_a?(String)
|
351
|
+
goods_url = dep
|
352
|
+
elsif dep.is_a?(Hash)
|
353
|
+
raise "Currently only URL-based dependencies on Goods files are supported!" unless dep["url"]
|
354
|
+
goods_url = dep["url"]
|
355
|
+
else
|
356
|
+
raise "Unexpected dependency type #{dep.class} when parsing DGD Manifest specs, item: #{dep.inspect}"
|
357
|
+
end
|
358
|
+
|
359
|
+
text_contents = URI.open(goods_url).read
|
360
|
+
local_path = shared_dir + "/goods/" + goods_url.tr("/\\ ", "_")
|
361
|
+
File.open(local_path, "wb") { |f| f.write(text_contents) }
|
362
|
+
dep_fields = JSON.parse text_contents
|
363
|
+
|
364
|
+
dependencies.push unbundled_json_to_spec(dep_fields)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
spec = GoodsSpec.new(@repo, name: fields["name"], source: source, source_details: source_details, paths: fields["paths"], dependencies: dependencies)
|
325
369
|
return spec
|
326
370
|
end
|
371
|
+
|
372
|
+
def ordered_specs
|
373
|
+
@specs.flat_map do |s|
|
374
|
+
deps = [s]
|
375
|
+
deps_to_add = s.dependencies
|
376
|
+
while(deps_to_add.size > 0)
|
377
|
+
next_deps = deps_to_add.flat_map { |dep| dep.dependencies }
|
378
|
+
deps = deps_to_add + deps
|
379
|
+
deps_to_add = next_deps
|
380
|
+
end
|
381
|
+
deps
|
382
|
+
end
|
383
|
+
end
|
327
384
|
end
|
328
385
|
|
329
386
|
class GoodsSpec
|
@@ -332,8 +389,9 @@ CONTENTS
|
|
332
389
|
attr_reader :source
|
333
390
|
attr_reader :source_details
|
334
391
|
attr_reader :paths
|
392
|
+
attr_reader :dependencies
|
335
393
|
|
336
|
-
def initialize(repo, name:, source:, source_details: {}, paths:)
|
394
|
+
def initialize(repo, name:, source:, source_details: {}, paths:, dependencies:)
|
337
395
|
@repo = repo
|
338
396
|
@name = name
|
339
397
|
@source = source
|
@@ -346,6 +404,7 @@ CONTENTS
|
|
346
404
|
end
|
347
405
|
|
348
406
|
@paths = cleaned_paths
|
407
|
+
@dependencies = dependencies
|
349
408
|
end
|
350
409
|
end
|
351
410
|
|
@@ -382,7 +441,7 @@ CONTENTS
|
|
382
441
|
"app_root": "app",
|
383
442
|
"goods": [
|
384
443
|
"# This is an example goods file - substitute your own.",
|
385
|
-
"https://raw.githubusercontent.com/
|
444
|
+
"https://raw.githubusercontent.com/ChatTheatre/dgd-tools/main/goods/skotos_httpd.goods"
|
386
445
|
],
|
387
446
|
"unbundled_goods": [
|
388
447
|
{
|
@@ -442,4 +501,114 @@ FILE_CONTENTS
|
|
442
501
|
puts "Successfully created project at #{@location}."
|
443
502
|
end
|
444
503
|
end
|
504
|
+
|
505
|
+
class DGDRuntimeConfig
|
506
|
+
attr_reader :app_root
|
507
|
+
|
508
|
+
DEFAULT_CONFIG = {
|
509
|
+
users: 100,
|
510
|
+
editors: 40,
|
511
|
+
swap_size: 1048576,
|
512
|
+
sector_size: 512,
|
513
|
+
swap_fragment: 4096,
|
514
|
+
static_chunk: 64512,
|
515
|
+
dynamic_chunk: 261120,
|
516
|
+
dump_interval: 3600,
|
517
|
+
typechecking: 2,
|
518
|
+
include_file: "/include/std.h",
|
519
|
+
include_dirs: ["/include", "~/include"],
|
520
|
+
auto_object: "/kernel/lib/auto",
|
521
|
+
driver_object: "/kernel/sys/driver",
|
522
|
+
create: "_F_create",
|
523
|
+
array_size: 16384,
|
524
|
+
objects: 262144,
|
525
|
+
call_outs: 16384,
|
526
|
+
}
|
527
|
+
CONFIG_KEYS = DEFAULT_CONFIG.keys.map(&:to_s) + [ "app_root", "ports", "telnet_ports", "dump_file", "statedir" ]
|
528
|
+
|
529
|
+
def initialize(config_data)
|
530
|
+
@app_root = config_data["app_root"] || "app"
|
531
|
+
@ports = {
|
532
|
+
"*" => 50100,
|
533
|
+
}
|
534
|
+
@telnet_ports = {
|
535
|
+
"*" => 50110,
|
536
|
+
}
|
537
|
+
@statedir = config_data["statedir"] || "state"
|
538
|
+
@dump_file = if config_data["dump_file"]
|
539
|
+
"../" + config_data["dump_file"]
|
540
|
+
else
|
541
|
+
"../#{@statedir}/dump"
|
542
|
+
end
|
543
|
+
@config = DEFAULT_CONFIG.dup
|
544
|
+
|
545
|
+
@raw_data = config_data
|
546
|
+
@config.keys.each do |prop|
|
547
|
+
# For now, assume and require that JSON data is the correct type if present
|
548
|
+
@config[prop] = config_data[prop.to_s] if config_data[prop.to_s]
|
549
|
+
end
|
550
|
+
unexpected_config_keys = config_data.keys - CONFIG_KEYS
|
551
|
+
unless unexpected_config_keys.empty?
|
552
|
+
raise "Unexpected key names in DGD configuration: #{unexpected_config_keys.inspect}!"
|
553
|
+
end
|
554
|
+
|
555
|
+
if config_data["telnet_ports"]
|
556
|
+
@telnet_ports = config_to_ports(config_data["telnet_ports"])
|
557
|
+
end
|
558
|
+
if config_data["ports"]
|
559
|
+
@ports = config_to_ports(config_data["ports"])
|
560
|
+
end
|
561
|
+
end
|
562
|
+
|
563
|
+
def config_to_ports(data)
|
564
|
+
if data.is_a?(Hash)
|
565
|
+
# TODO: verify that keys are IP addr strings and values are legal port numbers
|
566
|
+
return data
|
567
|
+
elsif data.is_a?(Array)
|
568
|
+
# TODO: verify that data is an array of legal integer port numbers
|
569
|
+
ports = {}
|
570
|
+
data.each { |p| ports["*"] = p }
|
571
|
+
return ports
|
572
|
+
elsif data.is_a?(Integer)
|
573
|
+
return { "*": data }
|
574
|
+
else
|
575
|
+
raise "dgd-manifest: not sure how to get port data from a #{data.class.name} -- #{data.inspect}!"
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
579
|
+
def as_file
|
580
|
+
return <<DGD_CONFIG
|
581
|
+
telnet_port = ([
|
582
|
+
#{@telnet_ports.map { |ip, p| "#{ip.inspect}:#{p}" }.join(",\n ") }
|
583
|
+
]); /* legacy telnet ports */
|
584
|
+
binary_port = ([
|
585
|
+
#{@ports.map { |ip, p| "#{ip.inspect}:#{p}" }.join(",\n ") }
|
586
|
+
]); /* binary ports */
|
587
|
+
directory = "./#{GENERATED_ROOT}";
|
588
|
+
|
589
|
+
users = #{@config[:users]}; /* max # of connections */
|
590
|
+
editors = #{@config[:editors]}; /* max # of built-in-editor sessions */
|
591
|
+
ed_tmpfile = "../#{@statedir}/ed"; /* proto editor tmpfile */
|
592
|
+
swap_file = "../#{@statedir}/swap"; /* swap file */
|
593
|
+
swap_size = #{@config[:swap_size]}; /* # sectors in swap file */
|
594
|
+
sector_size = #{@config[:sector_size]}; /* swap sector size */
|
595
|
+
swap_fragment = #{@config[:swap_fragment]}; /* fragment to swap out */
|
596
|
+
static_chunk = #{@config[:static_chunk]}; /* static memory chunk */
|
597
|
+
dynamic_chunk = #{@config[:dynamic_chunk]}; /* dynamic memory chunk */
|
598
|
+
dump_file = #{@dump_file.inspect}; /* dump file */
|
599
|
+
dump_interval = #{@config[:dump_interval]}; /* expected statedump interval in seconds */
|
600
|
+
|
601
|
+
typechecking = #{@config[:typechecking]}; /* level of typechecking (2 is highest) */
|
602
|
+
include_file = #{@config[:include_file].inspect}; /* standard include file */
|
603
|
+
include_dirs = ({ #{@config[:include_dirs].map(&:inspect).join(", ")} }); /* directories to search */
|
604
|
+
auto_object = #{@config[:auto_object].inspect}; /* auto inherited object */
|
605
|
+
driver_object = #{@config[:driver_object].inspect}; /* driver object */
|
606
|
+
create = #{@config[:create].inspect}; /* name of create function */
|
607
|
+
|
608
|
+
array_size = #{@config[:array_size]}; /* max array size */
|
609
|
+
objects = #{@config[:objects]}; /* max # of objects */
|
610
|
+
call_outs = #{@config[:call_outs]}; /* max # of callouts */
|
611
|
+
DGD_CONFIG
|
612
|
+
end
|
613
|
+
end
|
445
614
|
end
|
@@ -8,13 +8,21 @@ require "tempfile"
|
|
8
8
|
|
9
9
|
module SkotOS; end
|
10
10
|
|
11
|
-
|
11
|
+
class SkotOS::XMLObject; end
|
12
|
+
|
13
|
+
class << SkotOS::XMLObject
|
14
|
+
attr_accessor :merry_only
|
15
|
+
attr_accessor :ignore_whitespace
|
16
|
+
attr_accessor :ignore_types
|
17
|
+
end
|
12
18
|
|
13
19
|
class SkotOS::XMLObject
|
14
20
|
attr_reader :pretty
|
21
|
+
attr_reader :noko_doc
|
15
22
|
|
16
|
-
def initialize(pretty)
|
23
|
+
def initialize(pretty, noko_doc: nil)
|
17
24
|
@pretty = pretty
|
25
|
+
@noko_doc = noko_doc
|
18
26
|
end
|
19
27
|
|
20
28
|
def self.from_file(filename)
|
@@ -25,9 +33,7 @@ class SkotOS::XMLObject
|
|
25
33
|
remove_undiffed(doc)
|
26
34
|
|
27
35
|
pretty = doc.to_xml(indent:3)
|
28
|
-
|
29
|
-
#prune_whitespace(data)
|
30
|
-
SkotOS::XMLObject.new pretty
|
36
|
+
SkotOS::XMLObject.new pretty, noko_doc: doc
|
31
37
|
end
|
32
38
|
|
33
39
|
def self.diff_between(obj1, obj2, o1_name: "Object 1", o2_name: "Object 2")
|
@@ -40,8 +46,13 @@ class SkotOS::XMLObject
|
|
40
46
|
of1.close
|
41
47
|
of2.close
|
42
48
|
|
49
|
+
diff_opts = [ "c" ]
|
50
|
+
diff_opts += [ "b", "B" ] if self.ignore_whitespace
|
51
|
+
|
43
52
|
# Diff 'fails' if there's a difference between the two files.
|
44
|
-
|
53
|
+
cmd = "diff -#{diff_opts.join("")} #{of1.path} #{of2.path}"
|
54
|
+
#puts "Diff command: #{cmd}"
|
55
|
+
diff = system_call(cmd, fail_ok: true)
|
45
56
|
diff.sub!(of1.path, o1_name)
|
46
57
|
diff.sub!(of2.path, o2_name)
|
47
58
|
ensure
|
@@ -51,28 +62,35 @@ class SkotOS::XMLObject
|
|
51
62
|
diff
|
52
63
|
end
|
53
64
|
|
54
|
-
def self.skip_ignored_files(list)
|
55
|
-
|
56
|
-
|
57
|
-
|
65
|
+
def self.skip_ignored_files(list, base_dir)
|
66
|
+
if self.merry_only
|
67
|
+
list.select { |path| File.directory?(base_dir + "/" + path) ||
|
68
|
+
path[/.xml$/] || path[/.XML$/] }
|
69
|
+
else
|
70
|
+
list.select do |path|
|
71
|
+
!path[/,v$/] && # Ignore files ending in comma-v
|
72
|
+
!path[/-backup-\d+-\d+-\d+\.xml/] && # Ignore files ending in -backup-[DATE].xml
|
73
|
+
path != ".git" && # Ignore .git directories
|
74
|
+
path != "MOVED" # Ignore MOVED - it's a sort of recycle, waiting to be emptied
|
75
|
+
end
|
58
76
|
end
|
59
77
|
end
|
60
78
|
|
61
79
|
def self.diff_dirs(dir1, dir2)
|
62
|
-
entries1 = skip_ignored_files(Dir.glob("*", base: dir1).to_a)
|
63
|
-
entries2 = skip_ignored_files(Dir.glob("*", base: dir2).to_a)
|
80
|
+
entries1 = skip_ignored_files(Dir.glob("*", base: dir1).to_a, dir1)
|
81
|
+
entries2 = skip_ignored_files(Dir.glob("*", base: dir2).to_a, dir2)
|
64
82
|
|
65
83
|
only_in_1 = entries1 - entries2
|
66
84
|
only_in_2 = entries2 - entries1
|
67
85
|
in_both = entries1 & entries2
|
68
86
|
|
69
87
|
diff = []
|
70
|
-
diff << "Only in first: #{only_in_1.join(", ")}" unless only_in_1.empty?
|
71
|
-
diff << "Only in second: #{only_in_2.join(", ")}" unless only_in_2.empty?
|
88
|
+
diff << "Only in first: #{only_in_1.map { |s| dir1 + "/" + s }.join(", ")}" unless only_in_1.empty?
|
89
|
+
diff << "Only in second: #{only_in_2.map { |s| dir2 + "/" + s }.join(", ")}" unless only_in_2.empty?
|
72
90
|
|
73
91
|
in_both.each do |file|
|
74
|
-
in_1 =
|
75
|
-
in_2 =
|
92
|
+
in_1 = File.join dir1, file
|
93
|
+
in_2 = File.join dir2, file
|
76
94
|
if File.directory?(in_1) ^ File.directory?(in_2)
|
77
95
|
diff << "Only a directory in one, not both: #{dir1}/#{file}"
|
78
96
|
elsif File.directory?(in_1)
|
@@ -97,6 +115,101 @@ class SkotOS::XMLObject
|
|
97
115
|
end
|
98
116
|
end
|
99
117
|
end
|
118
|
+
|
119
|
+
rev = noko_single_node(doc.root, "Core:Property", attrs: { "property" => "revisions" })
|
120
|
+
noko_remove(rev) if rev
|
121
|
+
|
122
|
+
list = noko_single_node(doc.root, "Core:Property", attrs: { "property" => "#list#" })
|
123
|
+
list.remove if list
|
124
|
+
|
125
|
+
properties = noko_with_name_and_attrs(doc.root, "Core:Property")
|
126
|
+
properties.each do |prop_node|
|
127
|
+
prop_node.remove if prop_node.attribute("property").value.start_with?("sys:sync")
|
128
|
+
end
|
129
|
+
|
130
|
+
if self.merry_only
|
131
|
+
# Kill off all the non-Merry nodes
|
132
|
+
noko_remove_non_merry_nodes(doc.root)
|
133
|
+
end
|
134
|
+
|
135
|
+
if self.ignore_types
|
136
|
+
self.ignore_types.each do |ignored_type|
|
137
|
+
skipped = noko_with_name_and_attrs(doc.root, ignored_type)
|
138
|
+
skipped.each { |n| noko_remove(n) }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
base_combat = noko_single_node(doc.root, "Base:Combat")
|
143
|
+
if base_combat
|
144
|
+
base_strength = noko_single_node(base_combat, "Base:Strength", attrs: { "value" => "1" })
|
145
|
+
base_max_fatigue = noko_single_node(base_combat, "Base:MaxFatigue", attrs: { "value" => "1" })
|
146
|
+
if base_strength && base_max_fatigue && noko_non_text(base_combat.children).size == 2
|
147
|
+
next_text = base_combat.next
|
148
|
+
base_combat.remove
|
149
|
+
next_text.remove
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def self.noko_remove(node)
|
155
|
+
nn = node.next
|
156
|
+
nn.remove if nn.is_a?(Nokogiri::XML::Text)
|
157
|
+
node.remove
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.noko_single_node(node, name, attrs: {})
|
161
|
+
choices = noko_with_name_and_attrs(node, name, attrs)
|
162
|
+
if choices.size < 1
|
163
|
+
nil
|
164
|
+
elsif choices.size > 1
|
165
|
+
raise "Single-node search returned more than one node! #{name.inspect}, #{attrs.inspect}"
|
166
|
+
else
|
167
|
+
choices[0]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def self.noko_non_text(nodes)
|
172
|
+
nodes.select { |n| !n.is_a? Nokogiri::XML::Text }
|
173
|
+
end
|
174
|
+
|
175
|
+
def self.noko_with_name_and_attrs(node, name, attrs = {})
|
176
|
+
results = node.children.flat_map { |n| noko_with_name_and_attrs(n, name, attrs) }
|
177
|
+
if node.name == name &&
|
178
|
+
attrs.all? { |k, v| node.attribute(k).value == v }
|
179
|
+
results << node
|
180
|
+
end
|
181
|
+
results
|
182
|
+
end
|
183
|
+
|
184
|
+
def self.noko_remove_non_merry_nodes(root)
|
185
|
+
root.children.each do |node|
|
186
|
+
if node.name != "Core:PropertyContainer"
|
187
|
+
node.remove
|
188
|
+
next
|
189
|
+
end
|
190
|
+
|
191
|
+
node.children.each do |node2|
|
192
|
+
if node2.name != "Core:PCProperties"
|
193
|
+
node2.remove
|
194
|
+
next
|
195
|
+
end
|
196
|
+
|
197
|
+
node2.children.each do |property_node|
|
198
|
+
if property_node.name != "Core:Property" || property_node.attribute("property").value[0..5] != "merry:"
|
199
|
+
property_node.remove
|
200
|
+
next
|
201
|
+
end
|
202
|
+
# Leave the Merry node alone
|
203
|
+
end
|
204
|
+
|
205
|
+
if node2.children.size == 0
|
206
|
+
node2.remove
|
207
|
+
end
|
208
|
+
end
|
209
|
+
if node.children.size == 0
|
210
|
+
node.remove
|
211
|
+
end
|
212
|
+
end
|
100
213
|
end
|
101
214
|
|
102
215
|
def self.system_call(cmd, fail_ok: false)
|
data/lib/dgd-tools/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dgd-tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Noah Gibbs
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-03-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 1.10.5
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: optimist
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 3.0.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 3.0.1
|
27
41
|
description: dgd-tools supplies DGD Manifest and eventually perhaps other tools. DGD
|
28
42
|
Manifest is an experimental DGD library and packaging system.
|
29
43
|
email:
|
@@ -53,6 +67,7 @@ files:
|
|
53
67
|
- example_xml/t2/Thing.xml
|
54
68
|
- exe/dgd-manifest
|
55
69
|
- exe/skotos-xml-diff
|
70
|
+
- goods/chattheatre_kernellib.goods
|
56
71
|
- goods/skotos_httpd.goods
|
57
72
|
- lib/dgd-tools/manifest.rb
|
58
73
|
- lib/dgd-tools/skotos_xml_obj.rb
|