safedb 0.3.1011 → 0.4.1002

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +56 -19
  3. data/README.md +15 -15
  4. data/Rakefile +7 -0
  5. data/bin/safe +2 -2
  6. data/lib/{interprete.rb → cli.rb} +168 -121
  7. data/lib/controller/admin/README.md +47 -0
  8. data/lib/controller/admin/access.rb +47 -0
  9. data/lib/controller/admin/checkin.rb +83 -0
  10. data/lib/controller/admin/checkout.rb +57 -0
  11. data/lib/controller/admin/diff.rb +75 -0
  12. data/lib/{usecase → controller/admin}/export.rb +15 -14
  13. data/lib/controller/admin/goto.rb +52 -0
  14. data/lib/controller/admin/import.rb +54 -0
  15. data/lib/controller/admin/init.rb +113 -0
  16. data/lib/controller/admin/login.rb +88 -0
  17. data/lib/{usecase → controller/admin}/logout.rb +0 -0
  18. data/lib/controller/admin/open.rb +39 -0
  19. data/lib/{usecase → controller/admin}/token.rb +2 -2
  20. data/lib/controller/admin/tree.md +54 -0
  21. data/lib/{usecase → controller/admin}/use.rb +0 -0
  22. data/lib/controller/admin/view.rb +61 -0
  23. data/lib/{usecase → controller/api}/docker/README.md +0 -0
  24. data/lib/{usecase → controller/api}/docker/docker.rb +1 -1
  25. data/lib/{usecase → controller/api}/jenkins/README.md +0 -0
  26. data/lib/{usecase → controller/api}/jenkins/jenkins.rb +1 -1
  27. data/lib/{usecase → controller/api}/terraform/README.md +1 -1
  28. data/lib/{usecase → controller/api}/terraform/terraform.rb +1 -1
  29. data/lib/{usecase → controller/api}/vpn/README.md +1 -1
  30. data/lib/{usecase → controller/api}/vpn/vpn.ini +0 -0
  31. data/lib/{usecase → controller/api}/vpn/vpn.rb +0 -0
  32. data/lib/{usecase → controller}/config/README.md +0 -0
  33. data/lib/{usecase → controller}/edit/README.md +0 -0
  34. data/lib/controller/edit/editverse.rb +48 -0
  35. data/lib/controller/edit/put.rb +35 -0
  36. data/lib/controller/edit/remove.rb +29 -0
  37. data/lib/{usecase/update/README.md → controller/edit/rename.md} +0 -0
  38. data/lib/{usecase → controller}/files/README.md +1 -1
  39. data/lib/controller/files/read.rb +36 -0
  40. data/lib/{usecase/files/eject.rb → controller/files/write.rb} +15 -20
  41. data/lib/{usecase → controller}/id.rb +0 -0
  42. data/lib/controller/query/print.rb +26 -0
  43. data/lib/controller/query/queryverse.rb +39 -0
  44. data/lib/controller/query/show.rb +50 -0
  45. data/lib/{session/require.gem.rb → controller/requirer.rb} +13 -9
  46. data/lib/{usecase → controller}/set.rb +4 -4
  47. data/lib/controller/usecase.rb +244 -0
  48. data/lib/{usecase → controller}/verse.rb +0 -0
  49. data/lib/{usecase → controller}/visit/README.md +0 -0
  50. data/lib/{usecase → controller}/visit/visit.rb +0 -0
  51. data/lib/factbase/facts.safedb.net.ini +7 -7
  52. data/lib/{keytools/key.docs.rb → model/README.md} +102 -66
  53. data/lib/model/book.rb +484 -0
  54. data/lib/model/branch.rb +48 -0
  55. data/lib/model/checkin.feature +33 -0
  56. data/lib/{configs/README.md → model/configs.md} +4 -4
  57. data/lib/model/content.rb +214 -0
  58. data/lib/model/indices.rb +132 -0
  59. data/lib/model/safe_tree.rb +51 -0
  60. data/lib/model/state.inspect.rb +221 -0
  61. data/lib/model/state.migrate.rb +334 -0
  62. data/lib/model/text_chunk.rb +68 -0
  63. data/lib/{extension → utils/extend}/array.rb +0 -0
  64. data/lib/{extension → utils/extend}/dir.rb +0 -0
  65. data/lib/{extension → utils/extend}/file.rb +0 -0
  66. data/lib/utils/extend/hash.rb +76 -0
  67. data/lib/{extension → utils/extend}/string.rb +6 -6
  68. data/lib/{session/fact.finder.rb → utils/facts/fact.rb} +0 -0
  69. data/lib/utils/identity/identifier.rb +356 -0
  70. data/lib/{keytools/key.ident.rb → utils/identity/machine.id.rb} +67 -4
  71. data/lib/utils/inspect/inspector.rb +81 -0
  72. data/lib/{keytools/kdf.bcrypt.rb → utils/kdfs/bcrypt.rb} +0 -0
  73. data/lib/{keytools → utils/kdfs}/kdf.api.rb +16 -16
  74. data/lib/{keytools/key.local.rb → utils/kdfs/kdfs.rb} +40 -40
  75. data/lib/{keytools/kdf.pbkdf2.rb → utils/kdfs/pbkdf2.rb} +0 -0
  76. data/lib/{keytools/kdf.scrypt.rb → utils/kdfs/scrypt.rb} +0 -0
  77. data/lib/{keytools → utils}/key.error.rb +2 -2
  78. data/lib/{keytools → utils}/key.pass.rb +2 -2
  79. data/lib/{keytools → utils/keys}/key.64.rb +0 -0
  80. data/lib/{keytools → utils/keys}/key.rb +6 -2
  81. data/lib/{keytools/key.iv.rb → utils/keys/random.iv.rb} +0 -0
  82. data/lib/{logging/gem.logging.rb → utils/logs/logger.rb} +6 -5
  83. data/lib/{keytools/key.pair.rb → utils/store/datamap.rb} +48 -30
  84. data/lib/{keytools/key.db.rb → utils/store/datastore.rb} +38 -104
  85. data/lib/utils/store/merge-boys-school.json +40 -0
  86. data/lib/utils/store/merge-girls-school.json +48 -0
  87. data/lib/utils/store/merge-merged-data.json +56 -0
  88. data/lib/utils/store/struct.rb +75 -0
  89. data/lib/utils/store/test-commands.sh +24 -0
  90. data/lib/{keytools/key.now.rb → utils/time/timestamp.rb} +32 -21
  91. data/lib/version.rb +1 -1
  92. metadata +86 -73
  93. data/lib/extension/hash.rb +0 -33
  94. data/lib/keytools/key.algo.rb +0 -109
  95. data/lib/keytools/key.api.rb +0 -1326
  96. data/lib/keytools/key.id.rb +0 -322
  97. data/lib/modules/cryptology/amalgam.rb +0 -70
  98. data/lib/modules/cryptology/engineer.rb +0 -99
  99. data/lib/modules/mappers/dictionary.rb +0 -288
  100. data/lib/session/time.stamp.rb +0 -340
  101. data/lib/session/user.home.rb +0 -49
  102. data/lib/usecase/cmd.rb +0 -471
  103. data/lib/usecase/edit/delete.rb +0 -46
  104. data/lib/usecase/files/file_me.rb +0 -78
  105. data/lib/usecase/files/read.rb +0 -169
  106. data/lib/usecase/files/write.rb +0 -89
  107. data/lib/usecase/goto.rb +0 -57
  108. data/lib/usecase/import.rb +0 -157
  109. data/lib/usecase/init.rb +0 -61
  110. data/lib/usecase/login.rb +0 -72
  111. data/lib/usecase/open.rb +0 -71
  112. data/lib/usecase/print.rb +0 -40
  113. data/lib/usecase/put.rb +0 -81
  114. data/lib/usecase/show.rb +0 -138
  115. data/lib/usecase/update/rename.rb +0 -180
  116. data/lib/usecase/view.rb +0 -71
@@ -0,0 +1,47 @@
1
+
2
+ # Safe Administration Commands
3
+
4
+ A safe database is a collection of books and each database instance comprises of an index file and a collection of crypt files.
5
+
6
+ You can use your safe on many machines and on many shells within a machine. All this is synchronized via a **git repository** and with a single index file that is generally kept on removable (usb key) media.
7
+
8
+ ## safe branch admin commands
9
+
10
+ These commands handle **book and branch creation, instantiation and synchronization** between multiple shells.
11
+
12
+ | safe command | command purpose | cmd summary |
13
+ |:---------------------------- |:---------------------------------------------------- |:---------------- |
14
+ | **`safe init <BOOK_NAME>`** | instantiate a new safe database book | create book |
15
+ | **`safe login <BOOK_NAME>`** | create a new shell for instantiated book | instantiate book |
16
+ | **`safe commit`** | save the state of the book locally (like git commit) | save book |
17
+ | **`safe logout`** | delete references to this book and shell | delete branch |
18
+ | **`safe use <BOOK_NAME>`** | switch shell to using this logged in book | update branch |
19
+ | **`safe token`** | creates cryptographic keys for every shell | create key |
20
+
21
+
22
+ ## safe database sync commands
23
+
24
+ The **push** and **pull** commands synchronize your safe across many machines.
25
+
26
+ - **`safe pull --from=/path/to/usb/folder`** | pull safe assets to a machine with old state
27
+ - **`safe pull`** | uses index on usb drive if known and available (else refreshes local state)
28
+ - **`safe push --to=/path/to/usb/folder`** | pushes out safe assets from a machine with new state
29
+ - **`safe push`** | pushes out using index on usb drive if known and available
30
+
31
+ You must tell the safe where your remote git repository is.
32
+
33
+ - **`safe store git.pull.url https://github.com/devops4me/example.crypt.git`**
34
+ - **`safe store git.push.url git@safedb.crypt:devops4me/example.crypt.git`**
35
+
36
+ ## chicken and egg | public crypts
37
+
38
+ The safe is designed to **hold your private keys** so it would be chicken and egg if you needed a private key to access it.
39
+
40
+ The crypt files are designed to be utterly useless to those without both your usb key and your password. This is why
41
+
42
+ - **`git.pull.url`** can be publicly accessible from github **`https://github.com/...`**
43
+ - **`git.push.url`** is private **`git@<NAME>:<USER>/<REPO>`**
44
+
45
+ After you access your safe you then have the private key enabling you to push changes to your safe.
46
+
47
+ You can prevent access to your crypts by using a privately accessible git.pull.url.
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module SafeDb
4
+
5
+ # Parent to use cases like Init and Login that perform early
6
+ # initialize workflows.
7
+ class AccessUc < UseCase
8
+
9
+ attr_writer :password, :book_name
10
+
11
+
12
+ private
13
+
14
+
15
+ # Return true if the human secret for the parameter application name
16
+ # has been collected, transformed into a key, that key used to lock the
17
+ # power key, then secret and keys deleted, plus a trail of breadcrumbs
18
+ # sprinkled to allow the <b>branch crypt key to be regenerated</b>
19
+ # at the <b>next login</b>.
20
+ def is_book_initialized?()
21
+
22
+ KeyError.not_new( @book_name, self )
23
+ return false unless File.exists?( Indices::MASTER_INDICES_FILEPATH )
24
+ data_map = DataMap.new( Indices::MASTER_INDICES_FILEPATH )
25
+ return false unless data_map.has_section?( @book_id )
26
+ data_map.use( @book_id )
27
+
28
+ return contains_all_master_book_indices( data_map )
29
+
30
+ end
31
+
32
+
33
+ def contains_all_master_book_indices( data_map )
34
+ return false unless data_map.contains?( Indices::CONTENT_RANDOM_IV )
35
+ return false unless data_map.contains?( Indices::CONTENT_IDENTIFIER )
36
+ return false unless data_map.contains?( Indices::CRYPT_CIPHER_TEXT )
37
+ return false unless data_map.contains?( Indices::COMMIT_IDENTIFIER )
38
+ return true
39
+ end
40
+
41
+
42
+ end
43
+
44
+
45
+ end
46
+
47
+
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module SafeDb
4
+
5
+ # The <b>checkin use case</b> commits any changes made to the safe book into
6
+ # master. This is straightforward if the master's state has not been forwarded
7
+ # by a ckeckin from another (shell) branch.
8
+ #
9
+ # == master and branch not in sync
10
+ #
11
+ # The checkin and checkout use cases will be evolved to provide more options
12
+ # if the master state is out of sync.
13
+ #
14
+ # Six options present when the master state is ahead.
15
+ #
16
+ # == first checkout and then checkin
17
+ #
18
+ # The preferred manner of dealing with an out of sync state is to checkout
19
+ # first and then to checkin.
20
+ #
21
+ # - <tt>safe checkout --merge --branch</tt> | merge down (into branch) and branch wins on duplicates
22
+ # - <tt>safe checkout --merge --master</tt> | merge down (into branch) but master wins on duplicates
23
+ # - <tt>safe checkout --clobber</tt> | force branch to exactly mimic the master's state
24
+ #
25
+ # Once you chosent one of the above you can then <tt>safe checkin</tt> in a safe way.
26
+ #
27
+ # == bull in a china shop
28
+ #
29
+ # Merging down is more considered (and polite) to team members than merging up.
30
+ # If you know what you are doing you can merge or clobber up!
31
+ #
32
+ # - <tt>safe checkin --merge --branch</tt> | merge up (into master) and branch wins on duplicates
33
+ # - <tt>safe checkin --merge --master</tt> | merge up (into master) but master wins on duplicates
34
+ # - <tt>safe checkin --clobber</tt> | force master to exactly mimic our branch state
35
+ #
36
+ # == checkin | merge up mechanics
37
+ #
38
+ # The mechanics of a simple in-sync checkin is to
39
+ #
40
+ # - sync the master crypts to exactly mimic the branch crypts
41
+ # - tell master the content id of the book index file
42
+ # - tell master what the current random iv (initialization vector) is
43
+ # - create a new commit ID and set it on both master and branch
44
+ # - set the master's last updated date and time
45
+ #
46
+ class CheckIn < UseCase
47
+
48
+
49
+ # The <b>checkin use case</b> commits any changes made to the safe book into
50
+ # master. This is straightforward if the master's state has not been forwarded
51
+ # by a ckeckin from another (shell) branch.
52
+ def execute
53
+
54
+ book = Book.new()
55
+ book.print_book_mark()
56
+
57
+ unless book.can_checkin?()
58
+
59
+ puts "Cannot checkin as master has moved forward."
60
+ puts "First see the difference, then checkout, and then checkin."
61
+ puts ""
62
+ puts " safe diff"
63
+ puts " safe checkout"
64
+ puts " safe checkin"
65
+ puts ""
66
+ return
67
+
68
+ end
69
+
70
+ StateMigrate.checkin( book )
71
+
72
+ puts "The checkin was on #{KeyNow.readable()}\n"
73
+ puts "Checkin from branch to master was successful.\n"
74
+ puts ""
75
+
76
+
77
+ end
78
+
79
+
80
+ end
81
+
82
+
83
+ end
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module SafeDb
4
+
5
+ # The <b>checkout use case</b> commits any changes made to the safe book into
6
+ # master. This is straightforward if the master's state has not been forwarded
7
+ # by a ckeckin from another (shell) branch.
8
+ #
9
+ # == master and branch not in sync
10
+ #
11
+ # Checkins cannot occur when the master's state has been moved forward by another
12
+ # branch checkin. In these cases one needs to use the below sequence.
13
+ #
14
+ # - <tt>safe diff --checkout</tt> | diff will list what will the state changes during checkout
15
+ # - <tt>safe checkout</tt> | the actual merge down (from master to branch) that never deletes keys
16
+ # - <tt>safe checkin</tt> | now the checkin can proceed as the branch is in line with the master
17
+ #
18
+ # == checkout | merge up mechanics
19
+ #
20
+ # The mechanics of a simple in-sync checkout is to
21
+ #
22
+ # - sync the master crypts to exactly mimic the branch crypts
23
+ # - tell master the content id of the book index file
24
+ # - tell master what the current random iv (initialization vector) is
25
+ # - create a new commit ID and set it on both master and branch
26
+ # - set the master's last updated date and time
27
+ #
28
+ class CheckOut < UseCase
29
+
30
+
31
+ # The <b>checkout use case</b> commits any changes made to the safe book into
32
+ # master. This is straightforward if the master's state has not been forwarded
33
+ # by a ckeckin from another (shell) branch.
34
+ def execute
35
+
36
+ book = Book.new()
37
+
38
+ puts ""
39
+ puts " == Birth Day := #{book.init_time()}\n"
40
+ puts " == Book Name := #{book.book_name()} [#{book.book_id}]\n"
41
+ puts " == Book Mark := #{book.get_open_chapter_name()}/#{book.get_open_verse_name()}\n" if book.is_opened?()
42
+ puts ""
43
+
44
+ StateMigrate.checkout( book )
45
+ StateMigrate.copy_commit_id_to_branch( book )
46
+
47
+ puts "Checkout from master to branch was successful.\n"
48
+ puts ""
49
+
50
+
51
+ end
52
+
53
+
54
+ end
55
+
56
+
57
+ end
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module SafeDb
4
+
5
+ # The <b>diff use case</b> spells out the key differences between the safe book
6
+ # on the master line the one on the current working branch. There are two types
7
+ # of diff - a checkout diff or a checkin diff.
8
+ #
9
+ # == a checkout diff
10
+ #
11
+ # A checkout is effectively an incoming merge of the master's data
12
+ # structure into the working branch. With checkouts nothing ever gets
13
+ # deleted.
14
+ #
15
+ # No delete is self-evident in this list of only <tt>4 prophetic</tt>
16
+ # outcomes
17
+ #
18
+ # - this chapter will be added
19
+ # - this verse will be added
20
+ # - this line will be added
21
+ # - this branch's line value will be overwritten with the value from master
22
+ #
23
+ # == a checkin diff
24
+ #
25
+ # A checkout merges whilst a checkin is effectively a hard copy that destroys
26
+ # whatever is on the master making it exactly reflect the branch's current state.
27
+ #
28
+ # The three addition state changes prophesized by a checkout can also occur on
29
+ # checkins. However checkins can also prophesize that
30
+ #
31
+ # - this master's line value will be overwritten with the branch's value
32
+ # - this chapter will be removed
33
+ # - this verse will be removed
34
+ # - this line will be removed
35
+ #
36
+ class Diff < UseCase
37
+
38
+ # The checkin and checkout boolean flags that signal which way round to do the diff
39
+ attr_writer :checkin, :checkout
40
+
41
+ # The <b>diff use case</b> compares the database state of the branch with
42
+ # that of the master and displays the results without masking sensitive
43
+ # credentials.
44
+ def execute
45
+
46
+ book = Book.new()
47
+
48
+ print_both = @checkin.nil?() && @checkout.nil?()
49
+ print_checkin = !@checkin.nil?() || print_both
50
+ print_checkout = !@checkout.nil?() || print_both
51
+
52
+ puts ""
53
+ puts " == Birth Day := #{book.init_time()}\n"
54
+ puts " == Book Name := #{book.book_name()} [#{book.book_id}]\n"
55
+ puts " == Book Mark := #{book.get_open_chapter_name()}/#{book.get_open_verse_name()}\n" if book.is_opened?()
56
+ puts ""
57
+
58
+ master_data = book.to_master_data()
59
+ branch_data = book.to_branch_data()
60
+
61
+ StateInspect.checkout_prophecies( master_data, branch_data ) if print_checkout
62
+ StateInspect.checkin_prophecies( master_data, branch_data ) if print_checkin
63
+
64
+ puts ""
65
+ puts " master has #{master_data.length()} chapters, and #{book.get_master_verse_count()} verses.\n"
66
+ puts " branch has #{branch_data.length()} chapters, and #{book.get_branch_verse_count()} verses.\n"
67
+ puts ""
68
+
69
+ end
70
+
71
+
72
+ end
73
+
74
+
75
+ end
@@ -12,36 +12,37 @@ module SafeDb
12
12
 
13
13
  def execute
14
14
 
15
- return unless ops_key_exists?
16
- master_db = KeyApi.read_master_db()
15
+ book = Book.new()
17
16
 
18
17
  puts ""
19
18
  puts "### #############################################################\n"
20
- puts "### Book Birthday =>> #{KeyApi.to_db_create_date(master_db)}\n"
21
- puts "### The Book Name =>> #{KeyApi.to_db_domain_name(master_db)}\n"
22
- puts "### The Book (Id) =>> #{KeyApi.to_db_domain_id(master_db)}\n"
23
- puts "### #############################################################\n"
24
19
  puts "--- --------------------------------------------------------------\n"
20
+ puts ""
21
+ puts " The Birthday := #{book.init_time()}\n"
22
+ puts " Book Name := #{book.book_name()}\n"
23
+ puts " Book Id := #{book.book_id()}\n"
24
+ puts " Open Chapter := #{book.get_open_chapter_name()}\n" if book.has_open_chapter_name?()
25
+ puts " Open Verse := #{book.get_open_verse_name()}\n" if book.has_open_verse_name?()
26
+ puts ""
25
27
 
26
- chapters = KeyApi.to_matching_dictionary( master_db, ENVELOPE_KEY_PREFIX )
27
- export_filename = "safedb.#{KeyApi.read_app_id()}.#{KeyNow.yyjjj_hhmm_ss_nanosec()}.json"
28
+ export_filename = "safedb.#{KeyNow.yyjjj_hhmm_ss_nanosec()}.#{book.book_id()}.json"
28
29
  export_filepath = File.join( Dir.pwd, export_filename )
29
30
 
30
31
  exported_struct = {}
31
32
  verse_count = 0
32
33
 
33
- chapters.each_pair do | chapter_name, crumb_dictionary |
34
+ book.branch_chapter_keys().each_pair do | chapter_name, chapter_keys |
34
35
 
35
- chapter_struct = KeyDb.from_json( KeyApi.content_unlock( crumb_dictionary ) )
36
- verse_count += chapter_struct.length
37
- exported_struct.store( chapter_name, chapter_struct )
36
+ chapter_data = Content.unlock_branch_chapter( chapter_keys )
37
+ verse_count += chapter_data.length
38
+ exported_struct.store( chapter_name, chapter_data )
38
39
 
39
40
  end
40
41
 
41
- File.write( export_filepath, JSON.pretty_generate( exported_struct ) )
42
+ File.write( export_filepath, JSON.pretty_generate( exported_struct ) + "\n" )
42
43
 
43
44
  puts ""
44
- puts "Number of chapters exported >> #{chapters.length}"
45
+ puts "Number of chapters exported >> #{book.chapter_count()}"
45
46
  puts "Number of verses exported >> #{verse_count}"
46
47
  puts "The export filename is #{export_filename}"
47
48
  puts "The Present Working Directory is #{Dir.pwd}"
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module SafeDb
4
+
5
+ # Goto is a shortcut (or alias even) for the open command that takes an integer
6
+ # index that effectively specifies which chapter and verse to open.
7
+ #
8
+ # Use <b>view</b> to list the valid integer indices for each chapter and verse
9
+ # combination.
10
+ #
11
+ # View maps out and numbers each chapter/verse combination.
12
+ # Goto with the number effectively shortcuts the open pinpointer.
13
+ # Show prints out the verse lines at the opened path but masks any secrets.
14
+ # Tell also prints out the verse lines but unabashedly displays secrets.
15
+ class Goto < UseCase
16
+
17
+ # The index (number) starting with 1 of the envelope and key-path
18
+ # combination that should be opened.
19
+ attr_writer :index
20
+
21
+ def execute
22
+
23
+ book = Book.new()
24
+ goto_location = 0
25
+ book.branch_chapter_keys().each_pair do | chapter_name, chapter_keys |
26
+
27
+ chapter_data = Content.unlock_branch_chapter( chapter_keys )
28
+ chapter_data.each_key do | verse_name |
29
+
30
+ goto_location += 1
31
+ next unless @index.to_i == goto_location
32
+
33
+ open_uc = Open.new
34
+ open_uc.chapter = chapter_name
35
+ open_uc.verse = verse_name
36
+ open_uc.flow()
37
+
38
+ return
39
+
40
+ end
41
+
42
+
43
+ end
44
+
45
+
46
+ end
47
+
48
+
49
+ end
50
+
51
+
52
+ end
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module SafeDb
4
+
5
+ # The <b>import use case</b> takes a filepath parameter in order to pull in
6
+ # a <em>json</em> formatted data structure. It then proceeds to merge each
7
+ # chapter of the source JSON structure into the corresponding chapter of
8
+ # the destination, handling duplicate key/value pairs in a sensible way.
9
+ #
10
+ class Import < UseCase
11
+
12
+ attr_writer :import_filepath
13
+
14
+ # The <b>import use case</b> takes a filepath parameter in order to pull in
15
+ # a <em>json</em> formatted data structure. It then proceeds to merge each
16
+ # chapter of the source JSON structure into the corresponding chapter of
17
+ # the destination, handling duplicate key/value pairs in a sensible way.
18
+ def execute
19
+
20
+ book = Book.new()
21
+
22
+ abort "Cannot find the import file at path #{@import_filepath}" unless File.exists?( @import_filepath )
23
+
24
+ puts ""
25
+ puts "### #############################################################\n"
26
+ puts "--- -------------------------------------------------------------\n"
27
+ puts ""
28
+ puts " Book Name := #{book.book_name()}\n"
29
+ puts " Book Id := #{book.book_id()}\n"
30
+ puts " Import from := #{@import_filepath}\n"
31
+ puts " Import time := #{KeyNow.readable()}\n"
32
+ puts ""
33
+
34
+ new_verse_count = 0
35
+ data_store = DataStore.from_json( File.read( @import_filepath ) )
36
+ data_store.each_pair do | chapter_name, chapter_data |
37
+ book.import_chapter( chapter_name, chapter_data )
38
+ new_verse_count += chapter_data.length()
39
+ end
40
+
41
+ book.write()
42
+
43
+ puts ""
44
+ puts "#{data_store.length()} chapters and #{new_verse_count} verses were successfully imported.\n"
45
+ puts ""
46
+
47
+
48
+ end
49
+
50
+
51
+ end
52
+
53
+
54
+ end