dgd-tools 0.1.1 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2637c36239c1aabf37dbac03f0404cab8bb2ea493753bebc2710d44e03f78e11
4
- data.tar.gz: f544c13905cceb2c080385edc9122a4b89905700ac8195b97410ae58d829e5b6
3
+ metadata.gz: f64aa1b29bc2fb6a0c10292a25246ce4fbe5a43b7fa23dc19a84ab01abc58013
4
+ data.tar.gz: 60fb058d6f25ca80348e5236450ed3c5fe812137d04e0fce237d36b6b252dfca
5
5
  SHA512:
6
- metadata.gz: ce3e707b25251764367464866d71c64ece85e69cb8c39d2589d3342f263f9ba3c98270d3f130c05b481fac04d0c06e613d9992b87ab54bf99851e3fcd98ebc58
7
- data.tar.gz: 41acb15b29ca4667590ca59cace0a5563f1129845d205c32dbe662f6222aad9c174a09548e98f0e0b450c63b3e073cb5baa614eddbe390ab9e4084f1a8ca9e7d
6
+ metadata.gz: 30b54b93e1b4e5da44c7cf0bc6e526dd489d74301df20cd4d9644c69aab509416d3082d2646dd6394331f81643a92cbc24933141fdca024057ed6e003866b37a
7
+ data.tar.gz: 525305f71a39842d01f7ce99f3bce1d85d7dc0e5493411e09759cf003a8632609130281f40ba8ff25bf7edb8ffa73de5e9b53d3c3022c4143a8b99be70a9c4f9
data/.gitignore CHANGED
@@ -7,3 +7,5 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
  *.gem
10
+ test/data/**/dgd.config
11
+ test/data/*/.root
data/Gemfile.lock CHANGED
@@ -1,12 +1,16 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dgd-tools (0.1.1)
4
+ dgd-tools (0.1.5)
5
+ nokogiri (~> 1.10.5)
5
6
 
6
7
  GEM
7
8
  remote: https://rubygems.org/
8
9
  specs:
10
+ mini_portile2 (2.4.0)
9
11
  minitest (5.14.2)
12
+ nokogiri (1.10.10)
13
+ mini_portile2 (~> 2.4.0)
10
14
  rake (12.3.3)
11
15
 
12
16
  PLATFORMS
data/TODO ADDED
@@ -0,0 +1 @@
1
+ * Persistent data dirs. Symlinks in app-root dir for now?
data/bin/console CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "bundler/setup"
4
4
  require "dgd-tools/manifest"
5
+ require "dgd-tools/skotos_xml_obj"
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
data/dgd-tools.gemspec CHANGED
@@ -23,4 +23,6 @@ Gem::Specification.new do |spec|
23
23
  spec.bindir = "exe"
24
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
25
  spec.require_paths = ["lib"]
26
+
27
+ spec.add_runtime_dependency "nokogiri", "~>1.10.5"
26
28
  end
@@ -0,0 +1,42 @@
1
+ <object program="/base/sys/craftd">
2
+ <Base:CraftDaemon>
3
+ <Base:Craftables>
4
+ <Base:Craftable item="OBJ(Regent:Props:Fabric:blanket)"/>
5
+ <Base:Craftable item="OBJ(Regent:Staff:Evett:Items:Clothes:Top)"/>
6
+ <Base:Craftable item="OBJ(Regent:Props:Fabric:Cloth-cleaning)"/>
7
+ <Base:Craftable item="OBJ(Regent:Staff:Debbie:IC:General:orderbook)"/>
8
+ </Base:Craftables>
9
+ <Base:AllTools>
10
+ <Base:AllToolDependents tool="mop floor"/>
11
+ <Base:AllToolDependents tool="new">
12
+ <Base:OneToolDependent item="OBJ(Regent:Props:Fabric:blanket)"/>
13
+ <Base:OneToolDependent item="OBJ(Regent:Props:Fabric:Cloth-cleaning)"/>
14
+ <Base:OneToolDependent item="OBJ(Regent:Staff:Debbie:IC:General:orderbook)"/>
15
+ </Base:AllToolDependents>
16
+ <Base:AllToolDependents tool="regent:props:sewing:tools:needle"/>
17
+ <Base:AllToolDependents tool="regent:props:sewing:tools:scissors"/>
18
+ <Base:AllToolDependents tool="tool:heatable:container:watertight"/>
19
+ <Base:AllToolDependents tool="tool:heatsource:fire"/>
20
+ <Base:AllToolDependents tool="tools:needle">
21
+ <Base:OneToolDependent item="OBJ(Regent:Props:Fabric:blanket)"/>
22
+ <Base:OneToolDependent item="OBJ(Regent:Props:Fabric:Cloth-cleaning)"/>
23
+ </Base:AllToolDependents>
24
+ </Base:AllTools>
25
+ <Base:AllIngredients>
26
+ <Base:AllIngredientDependents ingredient="bolt">
27
+ <Base:OneIngredientDependent item="OBJ(Regent:Props:Fabric:blanket)"/>
28
+ <Base:OneIngredientDependent item="OBJ(Regent:Props:Fabric:Cloth-cleaning)"/>
29
+ </Base:AllIngredientDependents>
30
+ <Base:AllIngredientDependents ingredient="ingredient:candle"/>
31
+ <Base:AllIngredientDependents ingredient="ingredient:lantern-candle-empty"/>
32
+ <Base:AllIngredientDependents ingredient="ingredient:lantern:candle"/>
33
+ <Base:AllIngredientDependents ingredient="ingredients:tallow"/>
34
+ <Base:AllIngredientDependents ingredient="ingredients:wick:hemp"/>
35
+ <Base:AllIngredientDependents ingredient="new">
36
+ <Base:OneIngredientDependent item="OBJ(Regent:Props:Fabric:blanket)"/>
37
+ <Base:OneIngredientDependent item="OBJ(Regent:Staff:Evett:Items:Clothes:Top)"/>
38
+ <Base:OneIngredientDependent item="OBJ(Regent:Props:Fabric:Cloth-cleaning)"/>
39
+ </Base:AllIngredientDependents>
40
+ </Base:AllIngredients>
41
+ </Base:CraftDaemon>
42
+ </object>
@@ -0,0 +1,3 @@
1
+ <object program="/base/sys/materials">
2
+ <Base:Materials/>
3
+ </object>
@@ -0,0 +1,49 @@
1
+ <object program="/base/sys/properties">
2
+ <Base:PropertyTypes>
3
+ <Base:PropertyTypeIntList>
4
+ <Base:PropertyTypeInt property="page:allowall"/>
5
+ <Base:PropertyTypeInt property="skill:advancedefensive"/>
6
+ <Base:PropertyTypeInt property="skill:attackingdefensive"/>
7
+ <Base:PropertyTypeInt property="skill:cutoffensive"/>
8
+ <Base:PropertyTypeInt property="skill:dodgedefensive"/>
9
+ <Base:PropertyTypeInt property="skill:feintoffensive"/>
10
+ <Base:PropertyTypeInt property="skill:fumbledefensive"/>
11
+ <Base:PropertyTypeInt property="skill:guarddefensive"/>
12
+ <Base:PropertyTypeInt property="skill:idledefensive"/>
13
+ <Base:PropertyTypeInt property="skill:lang1"/>
14
+ <Base:PropertyTypeInt property="skill:lang2"/>
15
+ <Base:PropertyTypeInt property="skill:lang3"/>
16
+ <Base:PropertyTypeInt property="skill:lang4"/>
17
+ <Base:PropertyTypeInt property="skill:lang5"/>
18
+ <Base:PropertyTypeInt property="skill:lang6"/>
19
+ <Base:PropertyTypeInt property="skill:lang7"/>
20
+ <Base:PropertyTypeInt property="skill:recoverdefensive"/>
21
+ <Base:PropertyTypeInt property="skill:restdefensive"/>
22
+ <Base:PropertyTypeInt property="skill:retiredefensive"/>
23
+ <Base:PropertyTypeInt property="skill:salutedefensive"/>
24
+ <Base:PropertyTypeInt property="skill:teaching"/>
25
+ <Base:PropertyTypeInt property="skill:thrustoffensive"/>
26
+ <Base:PropertyTypeInt property="skill_study"/>
27
+ <Base:PropertyTypeInt property="skotos:currentlang"/>
28
+ </Base:PropertyTypeIntList>
29
+ <Base:PropertyTypeFloatList>
30
+ <Base:PropertyTypeFloat property="skill:fatigue"/>
31
+ </Base:PropertyTypeFloatList>
32
+ <Base:PropertyTypeStringList>
33
+ <Base:PropertyTypeString property="skotos:charname"/>
34
+ <Base:PropertyTypeString property="skotos:creator"/>
35
+ </Base:PropertyTypeStringList>
36
+ <Base:PropertyTypeObjectList>
37
+ <Base:PropertyTypeObject property="virtualhome:home"/>
38
+ <Base:PropertyTypeObject property="virtualhome:oubliette"/>
39
+ </Base:PropertyTypeObjectList>
40
+ <Base:PropertyTypeArrayList>
41
+ <Base:PropertyTypeArray property="startstory:skilllist:done"/>
42
+ <Base:PropertyTypeArray property="startstory:skilllist:left"/>
43
+ </Base:PropertyTypeArrayList>
44
+ <Base:PropertyTypeMappingList>
45
+ <Base:PropertyTypeMapping property="page:allow"/>
46
+ <Base:PropertyTypeMapping property="page:pending"/>
47
+ </Base:PropertyTypeMappingList>
48
+ </Base:PropertyTypes>
49
+ </object>
@@ -0,0 +1,41 @@
1
+ <object program="/base/obj/thing">
2
+ <Base:Thing>
3
+ <Ur:UrObject/>
4
+ <Base:Bulk immobile="false" mass="1" density="1"/>
5
+ <Base:Container flexible="false" transparent-container="false" public-container="false" tight="false" capacity="0" maxweight="0"/>
6
+ <Base:Misc gender="neuter" volition="false" weapon="false" default_stance="none" combinable="false" discrete="false" by_weight="false" tight="false" scriptrunner="false">
7
+ <Base:Edible value="false"/>
8
+ <Base:Potable value="false"/>
9
+ <Base:DrinkMessageFirst/>
10
+ <Base:DrinkMessageThird/>
11
+ <Base:Transparency value="false"/>
12
+ <Base:Unsafe value="false"/>
13
+ <Base:Safe value="false"/>
14
+ <Base:ClothesExpected value="false"/>
15
+ <Base:DieMessageFirst/>
16
+ <Base:DieMessageThird/>
17
+ </Base:Misc>
18
+ <Base:Details/>
19
+ <Base:Combat>
20
+ <Base:Strength value="1"/>
21
+ <Base:MaxFatigue value="1"/>
22
+ </Base:Combat>
23
+ <Base:Clothing>
24
+ <Base:SingleWear value="false"/>
25
+ </Base:Clothing>
26
+ <Base:Crafting see_level="0" do_level="0" time="0" attention="false" held="false">
27
+ <Base:Ingredients/>
28
+ <Base:Tools/>
29
+ <Base:CraftVerbs/>
30
+ </Base:Crafting>
31
+ <Base:InitialContents/>
32
+ <Base:InitialProperties/>
33
+ <Core:Properties>
34
+ <Core:Property property="revisions">
35
+ (\{ 1065557891, "the_exiled", "E" \})
36
+ </Core:Property>
37
+ <Core:Property property="skill:fatigue">1.0</Core:Property>
38
+ </Core:Properties>
39
+ <Notes:Notes/>
40
+ </Base:Thing>
41
+ </object>
@@ -0,0 +1,42 @@
1
+ <object program="/base/obj/thing" owner="bobo">
2
+ <Base:Thing>
3
+ <Ur:UrObject/>
4
+ <Base:Bulk immobile="false" mass="1" density="1"/>
5
+ <Base:Container flexible="false" transparent-container="false" public-container="false" tight="false" capacity="0" maxweight="0"/>
6
+ <Base:Misc gender="neuter" volition="false" weapon="false" default_stance="none" combinable="false" discrete="false" by_weight="false" tight="false" scriptrunner="false" bogusfield="nope">
7
+ <Base:Edible value="false"/>
8
+ <Base:Potable value="false"/>
9
+ <Base:DrinkMessageFirst/>
10
+ <Base:DrinkMessageThird/>
11
+ <Base:Transparency value="false"/>
12
+ <Base:Unsafe value="false"/>
13
+ <Base:Safe value="false"/>
14
+ <Base:ClothesExpected value="false"/>
15
+ <Base:DieMessageFirst/>
16
+ <Base:DieMessageThird/>
17
+ <Base:DieMessageFortySecond/>
18
+ </Base:Misc>
19
+ <Base:Details/>
20
+ <Base:Combat>
21
+ <Base:Strength value="1"/>
22
+ <Base:MaxFatigue value="1"/>
23
+ </Base:Combat>
24
+ <Base:Clothing>
25
+ <Base:SingleWear value="false"/>
26
+ </Base:Clothing>
27
+ <Base:Crafting see_level="0" do_level="0" time="0" attention="false" held="false">
28
+ <Base:Ingredients/>
29
+ <Base:Tools/>
30
+ <Base:CraftVerbs/>
31
+ </Base:Crafting>
32
+ <Base:InitialContents/>
33
+ <Base:InitialProperties/>
34
+ <Core:Properties>
35
+ <Core:Property property="revisions">
36
+ (\{ 1065557891, "the_exiled", "E" \})
37
+ </Core:Property>
38
+ <Core:Property property="skill:fatigue">1.0</Core:Property>
39
+ </Core:Properties>
40
+ <Notes:Notes/>
41
+ </Base:Thing>
42
+ </object>
@@ -0,0 +1,41 @@
1
+ <object program="/base/obj/thing">
2
+ <Base:Thing>
3
+ <Ur:UrObject/>
4
+ <Base:Bulk immobile="false" mass="1" density="1"/>
5
+ <Base:Container flexible="false" transparent-container="false" public-container="false" tight="false" capacity="0" maxweight="0"/>
6
+ <Base:Misc gender="neuter" volition="false" weapon="false" default_stance="none" combinable="false" discrete="false" by_weight="false" tight="false" scriptrunner="false">
7
+ <Base:Edible value="false"/>
8
+ <Base:Potable value="false"/>
9
+ <Base:DrinkMessageFirst/>
10
+ <Base:DrinkMessageThird/>
11
+ <Base:Transparency value="false"/>
12
+ <Base:Unsafe value="false"/>
13
+ <Base:Safe value="false"/>
14
+ <Base:ClothesExpected value="false"/>
15
+ <Base:DieMessageFirst/>
16
+ <Base:DieMessageThird/>
17
+ </Base:Misc>
18
+ <Base:Details/>
19
+ <Base:Combat>
20
+ <Base:Strength value="1"/>
21
+ <Base:MaxFatigue value="1"/>
22
+ </Base:Combat>
23
+ <Base:Clothing>
24
+ <Base:SingleWear value="false"/>
25
+ </Base:Clothing>
26
+ <Base:Crafting see_level="0" do_level="0" time="0" attention="false" held="false">
27
+ <Base:Ingredients/>
28
+ <Base:Tools/>
29
+ <Base:CraftVerbs/>
30
+ </Base:Crafting>
31
+ <Base:InitialContents/>
32
+ <Base:InitialProperties/>
33
+ <Core:Properties>
34
+ <Core:Property property="revisions">
35
+ (\{ 1065557891, "the_exiled", "E" \})
36
+ </Core:Property>
37
+ <Core:Property property="skill:fatigue">1.0</Core:Property>
38
+ </Core:Properties>
39
+ <Notes:Notes/>
40
+ </Base:Thing>
41
+ </object>
@@ -0,0 +1,42 @@
1
+ <object program="/base/obj/thing" owner="bobo">
2
+ <Base:Thing>
3
+ <Ur:UrObject/>
4
+ <Base:Bulk immobile="false" mass="1" density="1"/>
5
+ <Base:Container flexible="false" transparent-container="false" public-container="false" tight="false" capacity="0" maxweight="0"/>
6
+ <Base:Misc gender="neuter" volition="false" weapon="false" default_stance="none" combinable="false" discrete="false" by_weight="false" tight="false" scriptrunner="false" bogusfield="nope">
7
+ <Base:Edible value="false"/>
8
+ <Base:Potable value="false"/>
9
+ <Base:DrinkMessageFirst/>
10
+ <Base:DrinkMessageThird/>
11
+ <Base:Transparency value="false"/>
12
+ <Base:Unsafe value="false"/>
13
+ <Base:Safe value="false"/>
14
+ <Base:ClothesExpected value="false"/>
15
+ <Base:DieMessageFirst/>
16
+ <Base:DieMessageThird/>
17
+ <Base:DieMessageFortySecond/>
18
+ </Base:Misc>
19
+ <Base:Details/>
20
+ <Base:Combat>
21
+ <Base:Strength value="1"/>
22
+ <Base:MaxFatigue value="1"/>
23
+ </Base:Combat>
24
+ <Base:Clothing>
25
+ <Base:SingleWear value="false"/>
26
+ </Base:Clothing>
27
+ <Base:Crafting see_level="0" do_level="0" time="0" attention="false" held="false">
28
+ <Base:Ingredients/>
29
+ <Base:Tools/>
30
+ <Base:CraftVerbs/>
31
+ </Base:Crafting>
32
+ <Base:InitialContents/>
33
+ <Base:InitialProperties/>
34
+ <Core:Properties>
35
+ <Core:Property property="revisions">
36
+ (\{ 1065557891, "the_exiled", "E" \})
37
+ </Core:Property>
38
+ <Core:Property property="skill:fatigue">1.0</Core:Property>
39
+ </Core:Properties>
40
+ <Notes:Notes/>
41
+ </Base:Thing>
42
+ </object>
data/exe/dgd-manifest CHANGED
@@ -6,7 +6,31 @@ if ARGV.size == 0
6
6
  ARGV.push "install"
7
7
  end
8
8
 
9
+ if ARGV == ["--version"]
10
+ puts "dgd-tools version #{DGD::VERSION}"
11
+ exit
12
+ end
13
+
14
+ if ARGV.size == 1 && ["-h", "--help"].include?(ARGV[0])
15
+ puts <<HELP_INFO
16
+ dgd-manifest commands:
17
+
18
+ new [project_name]: create a new DGD-manifest project
19
+ test: make sure the dgd.manifest file is well-formed and usable
20
+ install: compile the DGD application to a config file and a root directory
21
+ HELP_INFO
22
+ exit
23
+ end
24
+
9
25
  case ARGV[0]
26
+ when "new"
27
+ unless ARGV.size == 2
28
+ puts "Usage: dgd-manifest new [project name]"
29
+ raise "Must supply exactly one argument to dgd-manifest new!"
30
+ end
31
+ appdir = DGD::Manifest::AppDirectory.new(File.expand_path ARGV[1])
32
+ appdir.name = ARGV[1]
33
+ appdir.create!
10
34
  when "test"
11
35
  unless File.exist?("dgd.manifest")
12
36
  raise "I don't see a dgd.manifest file in this directory!"
@@ -14,6 +38,7 @@ when "test"
14
38
  puts "Running dgd.manifest installer..."
15
39
  repo = DGD::Manifest::Repo.new
16
40
  repo.manifest_file("dgd.manifest")
41
+ repo.precheck(".")
17
42
  puts "Verified Manifest packages: this looks likely correct."
18
43
  when "install"
19
44
  unless File.exist?("dgd.manifest")
@@ -22,9 +47,13 @@ when "install"
22
47
  puts "Running DGD Manifest installer..."
23
48
  repo = DGD::Manifest::Repo.new
24
49
  repo.manifest_file("dgd.manifest")
25
- repo.assemble_app(".")
50
+ current_dir = File.expand_path(".")
51
+ repo.precheck(current_dir)
52
+ repo.assemble_app(current_dir)
53
+ puts "Assembled DGD application into #{current_dir}"
26
54
  when "server"
27
- puts "Starting DGD server... (not yet)"
55
+ puts "Starting DGD server..."
56
+ DGD::Manifest.system_call("~/.dgd-tools/dgd/bin/dgd dgd.config")
28
57
  else
29
58
  raise "Unrecognised #{$0} command: #{ARGV[0].inspect}!"
30
59
  end
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Diff multiple Skotos-XML-format objects dumped from a
4
+ # SkotOS-or-similar game to find out what updates should
5
+ # be merged between them.
6
+
7
+ require "dgd-tools/skotos_xml_obj"
8
+
9
+ if ARGV.size == 1 && ["-h", "--help"].include?(ARGV[0])
10
+ print <<HELP_INFO
11
+ skotos-xml-diff [file1] [file2]
12
+
13
+ OR
14
+
15
+ skotos-xml-diff [dir1] [dir2]
16
+ HELP_INFO
17
+ exit
18
+ end
19
+
20
+ if ARGV.size != 2
21
+ STDERR.puts "Usage: skotos-xml-diff <obj_or_dir_1> <obj_or_dir_2>"
22
+ exit -1
23
+ end
24
+
25
+ if File.directory?(ARGV[0]) ^ File.directory?(ARGV[1])
26
+ STDERR.puts "Please give two files or two directories, not one of each!"
27
+ exit -1
28
+ end
29
+
30
+ if File.directory?(ARGV[0])
31
+ diff = SkotOS::XMLObject.diff_dirs(*ARGV)
32
+ if diff.empty?
33
+ puts "No difference."
34
+ else
35
+ puts diff.join("\n\n=====\n\n")
36
+ end
37
+ else
38
+ obj1 = SkotOS::XMLObject.from_file(ARGV[0])
39
+ obj2 = SkotOS::XMLObject.from_file(ARGV[1])
40
+ diff = SkotOS::XMLObject.diff_between(obj1, obj2)
41
+ if diff.empty?
42
+ puts "No difference."
43
+ else
44
+ puts diff
45
+ end
46
+ end
@@ -9,7 +9,12 @@ module DGD; end
9
9
  module DGD::Manifest
10
10
  DGD_BUILD_COMMAND = %(make DEFINES='-DUINDEX_TYPE="unsigned int" -DUINDEX_MAX=UINT_MAX -DEINDEX_TYPE="unsigned short" -DEINDEX_MAX=USHRT_MAX -DSSIZET_TYPE="unsigned int" -DSSIZET_MAX=1048576' install
11
11
  )
12
- KERNEL_PATHS = ["include/kernel", "kernel"]
12
+ KERNEL_PATH_MAP = {
13
+ "src/kernel" => "/kernel",
14
+ "src/include" => "/include",
15
+ "src/doc/kernel" => "/doc/kernel"
16
+ }
17
+ KERNEL_PATHS = KERNEL_PATH_MAP.values
13
18
  DEFAULT_KERNELLIB_URL = "https://github.com/ChatTheatre/kernellib"
14
19
 
15
20
  GENERATED_ROOT = ".root"
@@ -25,24 +30,26 @@ module DGD::Manifest
25
30
  # This is a repo of everything DGD Manifest saves between runs.
26
31
  # It includes downloaded Git repos, Goods files and more.
27
32
  class Repo
28
- attr_reader :manifest_dir
33
+ attr_reader :shared_dir
29
34
 
30
35
  def initialize
36
+ @no_manifest_file = true
31
37
  @home = ENV["HOME"]
32
- @manifest_dir = "#{@home}/.dgd-tools"
33
- Dir.mkdir(@manifest_dir) unless File.directory?(@manifest_dir)
38
+ @shared_dir = "#{@home}/.dgd-tools"
39
+ Dir.mkdir(@shared_dir) unless File.directory?(@shared_dir)
40
+
34
41
  ["git", "goods"].each do |subdir|
35
- full_subdir = "#{@manifest_dir}/#{subdir}"
42
+ full_subdir = "#{@shared_dir}/#{subdir}"
36
43
  Dir.mkdir(full_subdir) unless File.directory?(full_subdir)
37
44
  end
38
45
 
39
- unless File.exist?("#{@manifest_dir}/dgd/bin/dgd")
40
- dgd_dir = "#{@manifest_dir}/dgd"
46
+ unless File.exist?("#{@shared_dir}/dgd/bin/dgd")
47
+ dgd_dir = "#{@shared_dir}/dgd"
41
48
  if File.directory?(dgd_dir)
42
49
  # Not clear to me what to do here...
43
50
  else
44
51
  DGD::Manifest.system_call("git clone https://github.com/ChatTheatre/dgd.git #{dgd_dir}")
45
- Dir.chdir("#{@manifest_dir}/dgd/src") do
52
+ Dir.chdir("#{@shared_dir}/dgd/src") do
46
53
  DGD::Manifest.system_call(DGD_BUILD_COMMAND)
47
54
  end
48
55
  end
@@ -55,45 +62,112 @@ module DGD::Manifest
55
62
  end
56
63
 
57
64
  def manifest_file(path)
58
- raise "Already have a dgd.manifest file!" if @manifest_file
65
+ raise "Already have a dgd.manifest file!" unless @no_manifest_file
59
66
 
67
+ @no_manifest_file = false
60
68
  @manifest_file ||= AppFile.new(self, path)
61
69
  end
62
70
 
63
- def assemble_app(location)
64
- dgd_root = "#{File.expand_path(location)}/#{GENERATED_ROOT}"
65
- app_path = "#{File.expand_path(location)}/#{@manifest_file.app_root}"
66
- FileUtils.rm_rf(dgd_root)
67
- FileUtils.cp_r(app_path, dgd_root)
71
+ protected
72
+
73
+ # This includes files to assemble... But also subdirectories and commands. This format is
74
+ # unstable and ugly, and should not be exposed to outside parties who might later depend on it.
75
+ def assembly_operations(location)
76
+ operations = []
68
77
 
69
- write_config_file("#{location}/dgd.config")
70
- specs = @manifest_file.specs
78
+ raise("No manifest file!") if @no_manifest_file
71
79
 
72
- specs.each do |spec|
80
+ @manifest_file.specs.each do |spec|
73
81
  git_repo = spec.source
74
- git_repo.use_details(spec.source_details)
82
+ git_repo.use_details(spec.source_details) # This sets things like checked-out branch
75
83
 
76
84
  spec.paths.each do |from, to|
85
+ # Note: git_repo.local_dir is an absolute path.
77
86
  from_path = "#{git_repo.local_dir}/#{from}"
78
- to_path = "#{dgd_root}/#{to}"
79
- to_dir = to_path.split("/")[0..-2].join("/")
80
- FileUtils.mkdir_p to_dir
81
- STDERR.puts "COPYING #{from_path.inspect} #{to_path.inspect}"
82
- FileUtils.cp_r(from_path, to_path)
87
+ if File.directory?(from_path)
88
+ files = Dir["#{from_path}/**/*"].to_a + Dir["#{from_path}/**/.*"].to_a
89
+ dirs = files.select { |file| File.directory?(file) }
90
+ non_dirs = files - dirs
91
+ operations << { cmd: "cp", from: from_path, to: to, dirs: dirs, non_dirs: non_dirs, comment: :single_dir }
92
+ elsif from_path["*"] # If from_path contains at least one asterisk
93
+ components = from.split("/")
94
+ first_wild_idx = components.index { |item| item["*"] }
95
+ no_wild_from_path = components[0..(first_wild_idx-1)].join("/")
96
+ wild_path = components[first_wild_idx..-1].join("/")
97
+
98
+ files = Dir["#{git_repo.local_dir}/#{no_wild_from_path}/#{wild_path}"].to_a
99
+ dirs = files.select { |file| File.directory?(file) }
100
+ dirs += files.map { |f| File.dirname(f) }
101
+ dirs.uniq!
102
+
103
+ non_dirs = files - dirs
104
+ operations << { cmd: "cp", from: "#{git_repo.local_dir}/#{no_wild_from_path}", to: to, dirs: dirs, non_dirs: non_dirs, comment: :path_wildcard }
105
+ else
106
+ # A single file
107
+ operations << { cmd: "cp", from: from_path, to: to, dirs: [], non_dirs: [from_path], comment: :single_file }
108
+ end
83
109
  end
84
110
  end
111
+
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
121
+ end
122
+
123
+ public
124
+
125
+ def assemble_app(location)
126
+ dgd_root = "#{File.expand_path(location)}/#{GENERATED_ROOT}"
127
+ FileUtils.rm_rf(dgd_root)
128
+
129
+ Dir.chdir(location) do
130
+ write_config_file("#{location}/dgd.config")
131
+ FileUtils.mkdir_p("#{location}/state") # Statedir for statedumps, editor files, etc.
132
+
133
+ assembly_operations(location).each do |sd_hash|
134
+ to_path = "#{dgd_root}/#{sd_hash[:to]}"
135
+
136
+ # Make appropriate dirs, including empty ones
137
+ sd_hash[:dirs].each do |dir|
138
+ FileUtils.mkdir_p dir.sub(sd_hash[:from], to_path)
139
+ end
140
+
141
+ # Copy all files
142
+ sd_hash[:non_dirs].each do |from_file|
143
+ to_file = from_file.sub(sd_hash[:from], "#{dgd_root}/#{sd_hash[:to]}")
144
+ to_dir = File.dirname(to_file)
145
+ FileUtils.mkdir_p to_dir
146
+ FileUtils.cp from_file, to_file
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ def precheck(location)
153
+ all_files = assembly_operations(location).flat_map { |sd| sd[:non_dirs] }
154
+
155
+ if all_files.size != all_files.uniq.size
156
+ repeated = all_files.uniq.select { |f| all_files.count(f) > 1 }
157
+ raise "Error in dgd.manifest! Repeated files: #{repeated.inspect} / #{all_files.inspect}"
158
+ end
85
159
  end
86
160
 
87
161
  def write_config_file(path)
88
162
  File.open(path, "wb") do |f|
89
163
  f.write <<CONTENTS
90
- /* These are SkotOS limits. They are enormous. They should
164
+ /* These are SkotOS limits. They are larger than you are likely to need. They should
91
165
  be configurable but they are not yet. */
92
166
  telnet_port = ([
93
167
  "*":50100 /* telnet port number */
94
168
  ]);
95
169
  binary_port = ([
96
- "*":50110, /* Failsafe */
170
+ "*":50110 /* Failsafe */
97
171
  ]); /* binary ports */
98
172
  directory = "./#{GENERATED_ROOT}";
99
173
 
@@ -134,7 +208,7 @@ CONTENTS
134
208
  @git_url = git_url
135
209
  @repo = repo
136
210
  local_path = git_url.tr("/\\", "_")
137
- @local_dir = "#{@repo.manifest_dir}/git/#{local_path}"
211
+ @local_dir = "#{@repo.shared_dir}/git/#{local_path}"
138
212
 
139
213
  if File.directory?(@local_dir)
140
214
  Dir.chdir(@local_dir) do
@@ -146,9 +220,7 @@ CONTENTS
146
220
  end
147
221
 
148
222
  def default_branch
149
- return @default_branch if @default_branch
150
- output = `git rev-parse --abbrev-ref origin/HEAD`.chomp
151
- @default_branch = output.gsub(/^origin\//, "")
223
+ @default_branch ||= `git rev-parse --abbrev-ref origin/HEAD`.chomp.gsub(/^origin\//, "")
152
224
  end
153
225
 
154
226
  def use_details(details)
@@ -174,7 +246,7 @@ CONTENTS
174
246
  @path = path
175
247
  @repo = repo
176
248
  raise("No such dgd.manifest file as #{path.inspect}!") unless File.exist?(path)
177
- contents = JSON.load(File.read(path))
249
+ contents = AppFile.parse_manifest_file(path)
178
250
 
179
251
  read_manifest_file(contents)
180
252
 
@@ -186,25 +258,41 @@ CONTENTS
186
258
  raise "Repeated (conflicting?) paths in dgd.manifest! #{repeated_paths.inspect}"
187
259
  end
188
260
 
189
- # Make sure the dgd.manifest file overrides either no kernel paths or both/all
190
- if KERNEL_PATHS.any? { |kp| output_paths.include?(kp) }
191
- unless KERNEL_PATHS.all? { |kp| output_paths.include?(kp) }
192
- raise "dgd.manifest file #{path.inspect} includes some Kernel Library paths but not all! All needed: #{KERNEL_PATHS}!"
193
- end
194
- puts "This dgd.manifest file overrides the Kernel Library with its own."
195
- else
196
- puts "This dgd.manifest needs the default Kernel Library."
197
- # This app has specified no kernellib paths -- add them
198
- git_repo = @repo.git_repo(DEFAULT_KERNELLIB_URL)
199
- kl_paths = { "src/kernel" => "/kernel", "src/include/kernel" => "/include/kernel", "src/doc/kernel" => "/doc/kernel" }
200
- klib_spec = GoodsSpec.new @repo, name: "default Kernel Library",
201
- source: git_repo, paths: kl_paths
202
- specs.push klib_spec
203
- end
261
+ ## Make sure the dgd.manifest file overrides either no kernel paths or both/all
262
+ #if KERNEL_PATHS.any? { |kp| output_paths.include?(kp) }
263
+ # unless KERNEL_PATHS.all? { |kp| output_paths.include?(kp) }
264
+ # raise "dgd.manifest file #{path.inspect} includes some Kernel Library paths but not all! All needed: #{KERNEL_PATHS}!"
265
+ # end
266
+ # puts "This dgd.manifest file overrides the Kernel Library with its own."
267
+ #else
268
+ # puts "This dgd.manifest needs the default Kernel Library."
269
+ # # This app has specified no kernellib paths -- add them
270
+ # git_repo = @repo.git_repo(DEFAULT_KERNELLIB_URL)
271
+ # klib_spec = GoodsSpec.new @repo, name: "default Kernel Library",
272
+ # source: git_repo, paths: KERNEL_PATH_MAP
273
+ # specs.unshift klib_spec
274
+ #end
204
275
 
205
276
  nil
206
277
  end
207
278
 
279
+ # Load the JSON and then remove comments
280
+ def self.parse_manifest_file(path)
281
+ contents = JSON.parse(File.read path)
282
+ remove_comments!(contents)
283
+ contents
284
+ end
285
+
286
+ def self.remove_comments!(items)
287
+ if items.is_a?(Hash)
288
+ items.delete_if { |k, v| k[0] == "#" }
289
+ items.values.each { |v| remove_comments!(v) }
290
+ elsif items.is_a?(Array)
291
+ items.delete_if { |i| i.is_a?(String) && i[0] == "#" }
292
+ items.each { |i| remove_comments!(i) }
293
+ end
294
+ end
295
+
208
296
  def read_manifest_file(contents)
209
297
  raise "Expected a top-level JSON object in dgd.manifest!" unless contents.is_a?(Hash)
210
298
 
@@ -273,4 +361,98 @@ CONTENTS
273
361
  @paths = cleaned_paths
274
362
  end
275
363
  end
364
+
365
+ class AppDirectory
366
+ attr_reader :location
367
+ attr_accessor :name
368
+
369
+ DEFAULT_FILE_LOCATIONS = {
370
+ "manifest" => "dgd.manifest",
371
+ "gitignore" => ".gitignore",
372
+ "gems_rb" => "gems.rb",
373
+ }
374
+ DEFAULT_EMPTY_DIRS = [ "app", "state" ]
375
+
376
+ def initialize(directory)
377
+ @location = directory
378
+ end
379
+
380
+ def gitignore_contents
381
+ <<~FILE_CONTENTS
382
+ # DGD Manifest files
383
+ .root
384
+ dgd.config
385
+ state/*
386
+ FILE_CONTENTS
387
+ end
388
+
389
+ def manifest_contents
390
+ <<FILE_CONTENTS
391
+ {
392
+ "name": "#{@name}",
393
+ "version": "0.1.0",
394
+ "description": "TODO: put description here",
395
+ "app_root": "app",
396
+ "goods": [
397
+ "# This is an example goods file - substitute your own.",
398
+ "https://raw.githubusercontent.com/noahgibbs/dgd-tools/main/goods/skotos_httpd.goods"
399
+ ],
400
+ "unbundled_goods": [
401
+ {
402
+ "#": "this is an example of unbundled goods - substitute your own",
403
+ "name": "kernellib",
404
+ "git": {
405
+ "url": "https://github.com/ChatTheatre/kernellib.git",
406
+ "branch": "master"
407
+ },
408
+ "paths": {
409
+ "src/doc/kernel": "doc/kernel",
410
+ "src/include/kernel": "include/kernel",
411
+ "src/include/*.h": "include",
412
+ "src/kernel": "kernel"
413
+ }
414
+ }
415
+ ]
416
+ }
417
+ FILE_CONTENTS
418
+ end
419
+
420
+ def gems_rb_contents
421
+ <<~FILE_CONTENTS
422
+ source "https://rubygems.org"
423
+
424
+ gem "dgd-tools", ">= #{DGD::VERSION}"
425
+ FILE_CONTENTS
426
+ end
427
+
428
+ def create!
429
+ if File.exist?(@location) && (!File.directory?(@location) || Dir["#{@location}/**"].size != 0)
430
+ raise "Cannot create a new DGD manifest project over a file or in an existing non-empty directory!"
431
+ end
432
+
433
+ puts "Creating new DGD manifest project at #{@location}..."
434
+ FileUtils.mkdir_p @location
435
+ Dir.chdir @location do
436
+ DEFAULT_FILE_LOCATIONS.each do |file_desc, file_location|
437
+ File.open(file_location, "wb") do |f|
438
+ contents = send("#{file_desc}_contents")
439
+ f.write(contents)
440
+ end
441
+ end
442
+
443
+ DEFAULT_EMPTY_DIRS.each do |dir|
444
+ FileUtils.mkdir dir
445
+ FileUtils.touch File.join(dir, ".keep")
446
+ end
447
+
448
+ result = system "bundle"
449
+ raise("Could not run bundler to install dgd-tools for #{@location}!") unless result
450
+
451
+ result = system "bundle exec dgd-manifest install"
452
+ raise("Error when running dgd-manifest for #{@location}!") unless result
453
+ end
454
+
455
+ puts "Successfully created project at #{@location}."
456
+ end
457
+ end
276
458
  end
@@ -0,0 +1,183 @@
1
+ require "dgd-tools/version"
2
+
3
+ # Nokogiri is unusually permissive as an XML parser, which is
4
+ # good - SkotOS XML objects don't parse with most XML parsers.
5
+ require "nokogiri"
6
+
7
+ require "tempfile"
8
+
9
+ module SkotOS; end
10
+
11
+ # TODO: remove <Core:Property property="revisions"> from anywhere in the XML tree
12
+
13
+ class SkotOS::XMLObject
14
+ attr_reader :pretty
15
+
16
+ def initialize(pretty)
17
+ @pretty = pretty
18
+ end
19
+
20
+ def self.from_file(filename)
21
+ # SkotOS files often have references to undefined namespaces,
22
+ # but we can get Nokogiri to parse it.
23
+ doc = Nokogiri::XML(File.read filename)
24
+
25
+ remove_undiffed(doc)
26
+
27
+ pretty = doc.to_xml(indent:3)
28
+ #data = doc.to_hash
29
+ #prune_whitespace(data)
30
+ SkotOS::XMLObject.new pretty
31
+ end
32
+
33
+ def self.diff_between(obj1, obj2, o1_name: "Object 1", o2_name: "Object 2")
34
+ of1 = Tempfile.new("skotos_xml_diff1_")
35
+ of2 = Tempfile.new("skotos_xml_diff2_")
36
+
37
+ begin
38
+ of1.write(obj1.pretty)
39
+ of2.write(obj2.pretty)
40
+ of1.close
41
+ of2.close
42
+
43
+ # Diff 'fails' if there's a difference between the two files.
44
+ diff = system_call("diff -c #{of1.path} #{of2.path}", fail_ok: true)
45
+ diff.sub!(of1.path, o1_name)
46
+ diff.sub!(of2.path, o2_name)
47
+ ensure
48
+ of1.unlink
49
+ of2.unlink
50
+ end
51
+ diff
52
+ end
53
+
54
+ def self.skip_ignored_files(list)
55
+ list.select do |path|
56
+ !path[/,v$/] && # Ignore files ending in comma-v
57
+ !path[/-backup-\d+-\d+-\d+\.xml/] # Ignore files ending in -backup-[DATE].xml
58
+ end
59
+ end
60
+
61
+ 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)
64
+
65
+ only_in_1 = entries1 - entries2
66
+ only_in_2 = entries2 - entries1
67
+ in_both = entries1 & entries2
68
+
69
+ 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?
72
+
73
+ in_both.each do |file|
74
+ in_1 = "#{dir1}/#{file}"
75
+ in_2 = "#{dir2}/#{file}"
76
+ if File.directory?(in_1) ^ File.directory?(in_2)
77
+ diff << "Only a directory in one, not both: #{dir1}/#{file}"
78
+ elsif File.directory?(in_1)
79
+ d = diff_dirs(in_1, in_2)
80
+ diff.concat(d)
81
+ else
82
+ o1 = from_file(in_1)
83
+ o2 = from_file(in_2)
84
+ this_diff = diff_between(o1, o2, o1_name: in_1, o2_name: in_2)
85
+ diff << this_diff unless this_diff.strip == ""
86
+ end
87
+ end
88
+ diff
89
+ end
90
+
91
+ def self.remove_undiffed(doc)
92
+ if doc.root && doc.root.element?
93
+ ignored_top_elements = ["program", "clone", "owner"]
94
+ ignored_top_elements.each do |attr|
95
+ if doc.root.attribute(attr)
96
+ doc.root.remove_attribute(attr)
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ def self.system_call(cmd, fail_ok: false)
103
+ f = Tempfile.new("system_call_xml_diff_")
104
+ begin
105
+ system(cmd, out: f)
106
+ unless fail_ok || $?.success?
107
+ f.rewind
108
+ out = f.read
109
+ raise "Error running command: #{cmd.inspect}!\n\nOutput:\n#{out}\n\n"
110
+ end
111
+ f.rewind
112
+ return f.read
113
+ ensure
114
+ f.close
115
+ f.unlink
116
+ end
117
+ end
118
+ end
119
+
120
+ =begin
121
+ # Abandoned approach follows
122
+ # Some code taken from: https://stackoverflow.com/a/10144623
123
+ class Nokogiri::XML::Node
124
+ TYPENAMES = {1=>'element',2=>'attribute',3=>'plaintext',4=>'cdata',8=>'comment'}
125
+ def to_hash
126
+ {kind:TYPENAMES[node_type],name:name}.tap do |h|
127
+ h.merge! nshref:namespace.href, nsprefix:namespace.prefix if namespace
128
+ h.merge! text:text
129
+ h.merge! attr:attribute_nodes.map(&:to_hash) if element?
130
+ h.merge! kids:children.map(&:to_hash) if element?
131
+ end
132
+ end
133
+ end
134
+ class Nokogiri::XML::Document
135
+ def to_hash; root.to_hash; end
136
+ end
137
+
138
+ class SkotOS::XMLObject
139
+ OBJ_FIELDS = [:kind, :name, :text, :attr, :nshref, :nsprefix]
140
+ def self.diff_between(obj1, obj2, diff = [])
141
+ single_obj1 = obj1.slice(*OBJ_FIELDS)
142
+ single_obj2 = obj2.slice(*OBJ_FIELDS)
143
+
144
+ this_diff = []
145
+ OBJ_FIELDS.each do |field|
146
+ if single_obj1[field] != single_obj2[field]
147
+ this_diff.concat ["+#{field}: #{single_obj2[field]}", "-#{field}: #{single_obj1[field]}"]
148
+ end
149
+ end
150
+
151
+ single_obj1[:kids]
152
+
153
+ diff
154
+ end
155
+
156
+ def self.prune_whitespace(data)
157
+ data[:text].gsub!(/\W+/, " ")
158
+ data[:text].strip!
159
+ new_kids = data[:kids].flat_map do |node|
160
+ if node[:kind] == "comment"
161
+ []
162
+ elsif node[:kind] == "plaintext"
163
+ new_text = node[:text].gsub(/\W+/, " ").strip
164
+ if new_text == ""
165
+ []
166
+ else
167
+ node[:text] = new_text
168
+ [node]
169
+ end
170
+ elsif node[:kind] == "element" || node[:kind] == "attribute"
171
+ node[:text].gsub!(/\W+/, " ")
172
+ node[:text].strip!
173
+ prune_whitespace(node)
174
+ [node]
175
+ else
176
+ raise "Is this illegal or did I just not anticipate it?"
177
+ end
178
+ end
179
+ data[:kids] = new_kids
180
+ nil
181
+ end
182
+ end
183
+ =end
@@ -1,3 +1,3 @@
1
1
  module DGD
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.6"
3
3
  end
metadata CHANGED
@@ -1,21 +1,36 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dgd-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Noah Gibbs
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-23 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2021-02-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.10.5
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.10.5
13
27
  description: dgd-tools supplies DGD Manifest and eventually perhaps other tools. DGD
14
28
  Manifest is an experimental DGD library and packaging system.
15
29
  email:
16
30
  - the.codefolio.guy@gmail.com
17
31
  executables:
18
32
  - dgd-manifest
33
+ - skotos-xml-diff
19
34
  extensions: []
20
35
  extra_rdoc_files: []
21
36
  files:
@@ -25,12 +40,22 @@ files:
25
40
  - Gemfile.lock
26
41
  - README.md
27
42
  - Rakefile
43
+ - TODO
28
44
  - bin/console
29
45
  - bin/setup
30
46
  - dgd-tools.gemspec
47
+ - example_xml/CraftDaemon.xml
48
+ - example_xml/Materials.xml
49
+ - example_xml/PropertyTypes.xml
50
+ - example_xml/Thing.xml
51
+ - example_xml/Thing2.xml
52
+ - example_xml/t1/Thing.xml
53
+ - example_xml/t2/Thing.xml
31
54
  - exe/dgd-manifest
55
+ - exe/skotos-xml-diff
32
56
  - goods/skotos_httpd.goods
33
57
  - lib/dgd-tools/manifest.rb
58
+ - lib/dgd-tools/skotos_xml_obj.rb
34
59
  - lib/dgd-tools/version.rb
35
60
  homepage: https://github.com/noahgibbs/dgd-tools
36
61
  licenses: