rbcli 0.1.10 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/CODE_OF_CONDUCT.md +1 -1
  4. data/Gemfile.lock +12 -12
  5. data/LICENSE.txt +674 -21
  6. data/README.md +80 -443
  7. data/bin/console +19 -0
  8. data/bin/setup +20 -0
  9. data/docs/404.html +639 -0
  10. data/docs/advanced/automatic_updates/index.html +791 -0
  11. data/docs/advanced/command_types/index.html +946 -0
  12. data/docs/advanced/distributed_state_locking/index.html +777 -0
  13. data/docs/advanced/hooks/index.html +836 -0
  14. data/docs/advanced/state_storage/index.html +957 -0
  15. data/docs/advanced/user_config_files/index.html +818 -0
  16. data/docs/assets/fonts/font-awesome.css +4 -0
  17. data/docs/assets/fonts/material-icons.css +13 -0
  18. data/docs/assets/fonts/specimen/FontAwesome.ttf +0 -0
  19. data/docs/assets/fonts/specimen/FontAwesome.woff +0 -0
  20. data/docs/assets/fonts/specimen/FontAwesome.woff2 +0 -0
  21. data/docs/assets/fonts/specimen/MaterialIcons-Regular.ttf +0 -0
  22. data/docs/assets/fonts/specimen/MaterialIcons-Regular.woff +0 -0
  23. data/docs/assets/fonts/specimen/MaterialIcons-Regular.woff2 +0 -0
  24. data/docs/assets/images/favicon.png +0 -0
  25. data/docs/assets/images/icons/bitbucket.1b09e088.svg +20 -0
  26. data/docs/assets/images/icons/github.f0b8504a.svg +18 -0
  27. data/docs/assets/images/icons/gitlab.6dd19c00.svg +38 -0
  28. data/docs/assets/javascripts/application.a59e2a89.js +1 -0
  29. data/docs/assets/javascripts/lunr/lunr.da.js +1 -0
  30. data/docs/assets/javascripts/lunr/lunr.de.js +1 -0
  31. data/docs/assets/javascripts/lunr/lunr.du.js +1 -0
  32. data/docs/assets/javascripts/lunr/lunr.es.js +1 -0
  33. data/docs/assets/javascripts/lunr/lunr.fi.js +1 -0
  34. data/docs/assets/javascripts/lunr/lunr.fr.js +1 -0
  35. data/docs/assets/javascripts/lunr/lunr.hu.js +1 -0
  36. data/docs/assets/javascripts/lunr/lunr.it.js +1 -0
  37. data/docs/assets/javascripts/lunr/lunr.jp.js +1 -0
  38. data/docs/assets/javascripts/lunr/lunr.multi.js +1 -0
  39. data/docs/assets/javascripts/lunr/lunr.no.js +1 -0
  40. data/docs/assets/javascripts/lunr/lunr.pt.js +1 -0
  41. data/docs/assets/javascripts/lunr/lunr.ro.js +1 -0
  42. data/docs/assets/javascripts/lunr/lunr.ru.js +1 -0
  43. data/docs/assets/javascripts/lunr/lunr.stemmer.support.js +1 -0
  44. data/docs/assets/javascripts/lunr/lunr.sv.js +1 -0
  45. data/docs/assets/javascripts/lunr/lunr.tr.js +1 -0
  46. data/docs/assets/javascripts/lunr/tinyseg.js +1 -0
  47. data/docs/assets/javascripts/modernizr.1aa3b519.js +1 -0
  48. data/docs/assets/stylesheets/application-palette.6079476c.css +2 -0
  49. data/docs/assets/stylesheets/application.ba0fd1a6.css +2 -0
  50. data/docs/development/code_of_conduct/index.html +883 -0
  51. data/docs/development/contributing/index.html +744 -0
  52. data/docs/development/license/index.html +715 -0
  53. data/docs/imported/changelog/index.html +853 -0
  54. data/docs/imported/quick_reference/index.html +1057 -0
  55. data/docs/index.html +732 -0
  56. data/docs/search/search_index.json +569 -0
  57. data/docs/sitemap.xml +93 -0
  58. data/docs/tutorial/10-getting_started/index.html +806 -0
  59. data/docs/tutorial/20-project_layout/index.html +972 -0
  60. data/docs/tutorial/30-your_first_command/index.html +906 -0
  61. data/docs/tutorial/40-options_parameters_and_arguments/index.html +1049 -0
  62. data/docs/tutorial/50-publishing/index.html +838 -0
  63. data/docs/whoami/index.html +709 -0
  64. data/docs-src/docs/advanced/automatic_updates.md +42 -0
  65. data/docs-src/docs/advanced/command_types.md +144 -0
  66. data/docs-src/docs/advanced/distributed_state_locking.md +33 -0
  67. data/docs-src/docs/advanced/hooks.md +65 -0
  68. data/docs-src/docs/advanced/logging.md +35 -0
  69. data/docs-src/docs/advanced/state_storage.md +117 -0
  70. data/docs-src/docs/advanced/user_config_files.md +47 -0
  71. data/docs-src/docs/development/code_of_conduct.md +74 -0
  72. data/docs-src/docs/development/contributing.md +49 -0
  73. data/docs-src/docs/development/license.md +10 -0
  74. data/docs-src/docs/imported/changelog.md +31 -0
  75. data/docs-src/docs/imported/quick_reference.md +150 -0
  76. data/docs-src/docs/index.md +38 -0
  77. data/docs-src/docs/tutorial/10-getting_started.md +41 -0
  78. data/docs-src/docs/tutorial/20-project_layout.md +115 -0
  79. data/docs-src/docs/tutorial/30-your_first_command.md +126 -0
  80. data/docs-src/docs/tutorial/40-options_parameters_and_arguments.md +251 -0
  81. data/docs-src/docs/tutorial/50-publishing.md +47 -0
  82. data/docs-src/docs/whoami.md +28 -0
  83. data/docs-src/makesite.sh +14 -0
  84. data/docs-src/mkdocs.yml +76 -0
  85. data/docs-src/runsite.sh +3 -0
  86. data/exe/rbcli +76 -5
  87. data/lib/rbcli/autoupdate/autoupdate.rb +24 -4
  88. data/lib/rbcli/autoupdate/gem_updater.rb +23 -2
  89. data/lib/rbcli/autoupdate/github_updater.rb +22 -1
  90. data/lib/rbcli/configuration/config.rb +22 -1
  91. data/lib/rbcli/configuration/configurate.rb +24 -2
  92. data/lib/rbcli/engine/command.rb +26 -6
  93. data/lib/rbcli/engine/load_project.rb +29 -3
  94. data/lib/rbcli/engine/parser.rb +25 -4
  95. data/lib/rbcli/logging/logging.rb +21 -0
  96. data/lib/rbcli/scriptwrapping/scriptwrapper.rb +30 -11
  97. data/lib/rbcli/stateful_systems/configuratestorage.rb +20 -0
  98. data/lib/rbcli/stateful_systems/state_storage.rb +20 -0
  99. data/lib/rbcli/stateful_systems/storagetypes/localstate.rb +20 -0
  100. data/lib/rbcli/stateful_systems/storagetypes/remote_state_connectors/dynamodb.rb +20 -0
  101. data/lib/rbcli/stateful_systems/storagetypes/remotestate_dynamodb.rb +20 -0
  102. data/lib/rbcli/util/hash_deep_symbolize.rb +43 -22
  103. data/lib/rbcli/util/string_colorize.rb +20 -0
  104. data/lib/rbcli/version.rb +21 -1
  105. data/lib/rbcli-tool/generators.rb +20 -0
  106. data/lib/rbcli-tool/mdless_fix.rb +20 -0
  107. data/lib/rbcli-tool/project.rb +27 -2
  108. data/lib/rbcli-tool/util.rb +20 -0
  109. data/lib/rbcli-tool.rb +20 -0
  110. data/lib/rbcli.rb +20 -0
  111. data/lib-sh/lib-rbcli.sh +19 -0
  112. data/rbcli.gemspec +22 -3
  113. data/skeletons/project/CODE_OF_CONDUCT.md +1 -1
  114. data/skeletons/project/README.md +17 -2
  115. data/skeletons/project/application/commands/command.erb +10 -8
  116. data/skeletons/project/application/commands/script.erb +3 -1
  117. data/skeletons/project/application/commands/scripts/script.sh +2 -2
  118. data/skeletons/project/application/options.rb +12 -3
  119. data/skeletons/project/config/autoupdate.rb +5 -2
  120. data/skeletons/project/config/storage.rb +7 -6
  121. data/skeletons/project/config/userspace.rb +6 -1
  122. data/skeletons/project/exe/executable +1 -1
  123. data/skeletons/project/lib/.keep +0 -0
  124. data/skeletons/project/untitled.gemspec +4 -4
  125. data/skeletons/project/{default_user_configs → userconf}/user_defaults.yml +0 -0
  126. metadata +85 -9
  127. data/examples/defaults.yml +0 -4
  128. data/examples/myscript.sh +0 -23
  129. data/examples/mytool +0 -95
@@ -0,0 +1,42 @@
1
+ # Automatic Updates
2
+
3
+ RBCli can automatically notify users when an update is available. If `force_update` is set (see below), RBCli can halt execution until the user updates their application.
4
+
5
+ Two sources are currently supported: __Github__ (including Enterprise) and __RubyGems__.
6
+
7
+ ## GitHub Update Check
8
+
9
+ The GitHub update check works best when paired with GitHub's best practices on releases, where new releases are tagged on master with the format __vX.X.X__. See [Github's release documentation][github_release_documentation] to learn more.
10
+
11
+ RBCli will check your github repo's tags and compare that version number with one specified in your application at `config/version.rb`.
12
+
13
+ ```ruby
14
+ autoupdate github_repo: '<your_user>/<your_repo>', access_token: nil, enterprise_hostname: nil, force_update: false, message: nil
15
+ ```
16
+ The `github_repo` should point to the repo using the `user/repo` syntax.
17
+
18
+ The `access_token` can be overridden by the user via their config file, so it can be left as `nil` if you enable [Userspace Configuration][userspace_configuration]. The token is not needed at all if using a public repo. For instructions on generating a new access token, see [here][github_generate_token].
19
+
20
+ The `enterprise_hostname` setting allows you to point RBCli at a local GitHub Enterprise server.
21
+
22
+ Setting `force_update: true` will halt execution if an update is available, forcing the user to update.
23
+
24
+ The `message` parameter allows setting a custom message that will be displayed when an update is available. Leaving it as `nil` will use the default message provided by RBCli.
25
+
26
+ ## Rubygems.org Update Check
27
+
28
+ The Rubygems update check will check if there is a new published version of the gem on Rubygems.org. The latest published version is compared to the version number you configured RBCli with.
29
+
30
+ ```ruby
31
+ autoupdate gem: '<your_gem>', force_update: false, message: nil
32
+ ```
33
+
34
+ The `gem` parameter should simply state the name of the gem.
35
+
36
+ Setting `force_update: true` will halt execution if an update is available, forcing the user to update.
37
+
38
+ The `message` parameter allows setting a custom message that will be displayed when an update is available. Leaving it as `nil` will use the default message provided by RBCli.
39
+
40
+ [github_release_documentation]: https://help.github.com/articles/creating-releases/
41
+ [userspace_configuration]: user_config_files.md
42
+ [github_generate_token]: https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
@@ -0,0 +1,144 @@
1
+ # Advanced Command Types
2
+
3
+ RBCli has three different command types:
4
+
5
+ * __Standard Commands__ (Ruby-based)
6
+ * __Scripted Commands__ (Ruby+Bash based)
7
+ * __External Commands__ (Wrapping a 3rd party application)
8
+
9
+
10
+ This document is provided to be a reference. If you would like an in-depth tutorial, please see [Your First Command][your_first_command].
11
+
12
+
13
+ ## General Command Structure
14
+
15
+ Commands in RBCli are created by subclassing `Rbcli::Command`. All commands share a certain common structure:
16
+
17
+ ```ruby
18
+ class List < Rbcli::Command # Declare a new command by subclassing Rbcli::Command
19
+ description 'TODO: Description goes here' # (Required) Short description for the global help
20
+ usage <<-EOF
21
+ TODO: Usage text goes here
22
+ EOF # (Required) Long description for the command-specific help
23
+ parameter :force, 'Force testing', type: :boolean, default: false, required: false # (Optional, Multiple) Add a command-specific CLI parameter. Can be called multiple times
24
+
25
+ config_default :myopt2, description: 'My Option #2', default: 'Default Value Here' # (Optional, Multiple) Specify an individual configuration parameter and set a default value. These will also be included in generated user config.
26
+ # Alternatively, you can simply create a yaml file in the `default_user_configs` directory in your project that specifies the default values of all options
27
+ end
28
+ ```
29
+
30
+ * `description`
31
+ * A short description of the command, which will appear in the top-level help (when the user runs `mytool -h`).
32
+ * `usage`
33
+ * A description of how the command is meant to be used. This description can be as long as you want, and can be as in-depth as you'd like. It will show up as a long, multi-line description when the user runs the command-sepcific help (`mytool list -h`).
34
+ * `parameter`
35
+ * Command-line tags that the user can enter that are specific to only this command. We will get into these in the next section on [Options, Parameters, and Arguments][parameters_documentation]
36
+ * `config_default`
37
+ * This sets a single item in the config file that will be made available to the user. More information can be found in the documentation on [User Config Files][user_config_documentation]
38
+
39
+ ## Standard Commands
40
+
41
+ Standard commands are written as ruby code. To create a standard command called `list`, run:
42
+
43
+ ```bash
44
+ rbcli command --name=list
45
+ #or
46
+ rbcli command -n list
47
+ ```
48
+
49
+ A standard command can be identified by the presence of an `action` block in the definition:
50
+
51
+ ```ruby
52
+ class List < Rbcli::Command
53
+ action do |params, args, global_opts, config|
54
+ # Code goes here
55
+ end
56
+ end
57
+ ```
58
+
59
+ Your application's __parameters__, __arguments__, __options__, and __config__ are available in the variables passed into the block. For more information on these, see [Options, Parameters, and Arguments][parameters_documentation].
60
+
61
+
62
+ ## Scripted Commands
63
+
64
+ Scripted commands are part Ruby, part Bash scripting. They are a good choice to use if you feel something might be easier or more performant to script with Bash, or if you already have a Bash script you'd like to use in your project. You can create one with:
65
+
66
+ ```bash
67
+ rbcli script -n list
68
+ ```
69
+
70
+ This will create two files in your RBCli project: a Ruby file with the common command declaration (see [General Command Structure](#general-command-structure)), and a bash script in the folder `application/commands/scripts/`.
71
+
72
+ You can tell a command is a script by the line:
73
+
74
+ ```ruby
75
+ class List < Rbcli::Command
76
+ extern path: :default # (Required): Do not edit this line. Do delete it if you wish to manually specify a script path and set environment variables.
77
+ end
78
+ ```
79
+
80
+ RBCli will pass along your applications config and CLI parameters through JSON environment variables. To make things easy, a Bash library is provided that makes retrieving and parsing these variables easy. It is already imported when you generate the command, with the line:
81
+
82
+ ```bash
83
+ source $(echo $(cd "$(dirname $(gem which rbcli))/../lib-sh" && pwd)/lib-rbcli.sh)
84
+ ```
85
+
86
+ This will find the library which is stored on the system as part of the RBCli gem.
87
+
88
+ You can then retrieve the values present in your variables like such:
89
+
90
+ ```bash
91
+ rbcli params
92
+ rbcli args
93
+ rbcli global_opts
94
+ rbcli config
95
+ rbcli myvars
96
+
97
+ echo "Usage Examples:"
98
+ echo "Log Level: $(rbcli config .logger.log_level)"
99
+ echo "Log Target: $(rbcli config .logger.log_target)"
100
+ echo "First Argument (if passed): $(rbcli args .[0])"
101
+ ```
102
+
103
+ For your convenience, the script will have all the instructions needed there. For more instructions on how to use JQ syntax to parse values, see the [JQ documentation][jq_documentation].
104
+
105
+ ## External Commands
106
+
107
+ External Commands are used to wrap 3rd party applications. RBCli accomplishes this by allowing you to set environment variables and command line parameters based on your input variables.
108
+
109
+ RBCli provides this feature through the `extern` keyword. It provides two modes -- __direct path__ and __variable path__ -- which work similarly.
110
+
111
+
112
+ ### Direct Path Mode
113
+
114
+ Direct path mode is the simpler mode of the two External Command modes. It allows you to provide a specific command with environment variables set, though it does not allow using RBCli parameters, arguments, options, and config.
115
+
116
+ ```ruby
117
+ class List < Rbcli::Command
118
+ extern path: 'path/to/application', envvars: {MYVAR: 'some_value'} # (Required) Runs a given application, with optional environment variables, when the user runs the command.
119
+ end
120
+ ```
121
+
122
+ Here, we supply a string to run the command. We can optioanlly provide environment variables which will be set for the external application.
123
+
124
+ ### Variable Path Mode
125
+
126
+ Variable Path mode works the same as Direct Path Mode, only instead of providing a string we provide a block that returns a string (which will be the command executed). This allows us to generate different commands based on the CLI parameters that the user passed, or pass configuration as CLI parameters to the external application:
127
+
128
+ ```ruby
129
+ class Test < Rbcli::Command
130
+ extern envvars: {MY_OTHER_VAR: 'another_value'} do |params, args, global_opts, config| # Alternate usage. Supplying a block instead of a path allows us to modify the command based on the arguments and configuration supplied by the user. This allows passing config settings as command line arguments to external applications. The block must return a string, which is the command to be executed.
131
+ cmd = '/path/to/application'
132
+ cmd += ' --test-script foo --ignore-errors' if params[:force]
133
+ cmd
134
+ end
135
+ end
136
+ ```
137
+
138
+ __NOTE__: Passing user-supplied data as part of the command string may be a security risk (example: `/path/to/application --name #{params[:name]}`). It is highly recommended to provide the fixed strings yourself, and only select which strings are used based on the variables provided. This is demonstrated in the example above.
139
+
140
+
141
+ [your_first_command]: ../tutorial/30-your_first_command.md
142
+ [parameters_documentation]: ../tutorial/40-options_parameters_and_arguments.md
143
+ [user_config_documentation]: ../advanced/user_config_files.md
144
+ [jq_documentation]: https://stedolan.github.io/jq/manual/
@@ -0,0 +1,33 @@
1
+ # Distributed Locking and State Sharing
2
+
3
+ Distributed Locking allows a [Remote State][state_storage] to be shared among multiple users of the application to make writes appear atomic between sessions. To use it, simply set the `locking:` parameter to `true` when enabling remote state.
4
+
5
+ This is how locking works:
6
+
7
+ 1. The application attempts to acquire a lock on the remote state when you first access it
8
+ 2. If the backend is locked by a different application, wait and try again
9
+ 3. If it succeeds, the lock is held and refreshed periodically
10
+ 4. When the application exits, the lock is released
11
+ 5. If the application does not refresh its lock, or fails to release it when it exits, the lock will automatically expire within 60 seconds
12
+ 6. If another application steals the lock (unlikely but possible), and the application tries to save data, a `StandardError` will be thrown
13
+ 7. You can manually attempt to lock/unlock by calling `Rbcli.remote_state.lock` or `Rbcli.remote_state.unlock`, respectively.
14
+
15
+
16
+ ## Manual Locking
17
+
18
+ Remember: all state in Rbcli is lazy-loaded. Therefore, RBCli wll only attempt to lock the data when you first try to access it. If you need to make sure that the data is locked before executing a block of code, use:
19
+
20
+ ```ruby
21
+ Rbcli.remote_state.refresh
22
+ ```
23
+
24
+ to force the lock and retrieve the latest data. You can force an unlock by calling:
25
+
26
+ ```ruby
27
+ Rbcli.remote_state.disconnect
28
+ ```
29
+
30
+ Even if you do not want to store any data, you can leverage manual locking to control access to a different shared resource, such as a stateful API. For example, if you write a cloud deployment toolkit, you can ensure that only one user is attempting to modify a deployment at any given time.
31
+
32
+
33
+ [state_storage]: state_storage.md
@@ -0,0 +1,65 @@
1
+ # Execution Hooks
2
+
3
+ RBCli provides you with hooks that can be used to have code execute at certain places in the execution chain. These hooks are optional, and do not have to be defined for your application to run.
4
+
5
+ All hooks will be created in the `hooks/` folder in your project.
6
+
7
+ ## The Defailt Action Hook
8
+
9
+ The Default hook is called when a user calls your application without providing a command. If the hook is not provided, the application will automatically display the help text (the same as running it with `-h`).
10
+
11
+ To create it in your project, run:
12
+
13
+ ```bash
14
+ rbcli hook --default
15
+ # or
16
+ rbcli hook -d
17
+ ```
18
+
19
+ You will then find the hook under `hooks/default_action.rb`.
20
+
21
+
22
+ ## The Pre-Execution Hook
23
+
24
+ The Pre-Execution hook is called after the global command line options are parsed and before a command is executed.
25
+
26
+ To create it in your project, run:
27
+
28
+ ```bash
29
+ rbcli hook --pre
30
+ # or
31
+ rbcli hook -p
32
+ ```
33
+
34
+ You will then find the hook under `hooks/pre_execution.rb`.
35
+
36
+ ## The Post-Execution Hook
37
+
38
+ The Pre-Execution hook is called after a command is executed.
39
+
40
+ To create it in your project, run:
41
+
42
+ ```bash
43
+ rbcli hook --post
44
+ # or
45
+ rbcli hook -o
46
+ ```
47
+
48
+ You will then find the hook under `hooks/post_execution.rb`.
49
+
50
+ ## The First-Run Hook
51
+
52
+ The First-Run hook is called the first time a user executes your application. Using the first-run hook requires enabling [Local State Storage][state_storage] for persistence.
53
+
54
+ To create it in your project, run:
55
+
56
+ ```bash
57
+ rbcli hook --firstrun
58
+ # or
59
+ rbcli hook -f
60
+ ```
61
+
62
+ You will then find the hook under `hooks/first_run.rb`.
63
+
64
+
65
+ [state_storage]: state_storage.md
@@ -0,0 +1,35 @@
1
+ # Logging
2
+
3
+ Logging with RBCli is straightforward - it looks at the config file for logging settings, and instantiates a single, globally accessible [Logger][ruby_logger] object. You can access it within a standard command like this:
4
+
5
+ ```ruby
6
+ Rbcli::log.info { 'These logs can go to STDERR, STDOUT, or a file' }
7
+ ```
8
+
9
+ ## Enabling Logging
10
+
11
+ To enable logging, simply set the default values in the `config/logging.rb` file:
12
+
13
+ ```ruby
14
+ log_level :info
15
+ log_target 'stderr'
16
+ ```
17
+
18
+ * `log_level`
19
+ * You can set the default log level using either numeric or standard Ruby logger levels: 0-5, or DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
20
+ * `log_target`
21
+ * This specifies where the logs will be placed. Valid values are nil (disables logging), 'STDOUT', 'STDERR', or a file path (all as strings).
22
+
23
+ ## Userspace Config Overrides
24
+
25
+ If [Userspace Configuration][userspace_configuration] is enabled, these options will also be present in the user's config file to override defaults:
26
+
27
+ ```yaml
28
+ # Log Settings
29
+ logger:
30
+ log_level: warn # 0-5, or DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN
31
+ log_target: stderr # STDOUT, STDERR, or a file path
32
+ ```
33
+
34
+ [ruby_logger]: https://ruby-doc.org/stdlib-2.4.0/libdoc/logger/rdoc/Logger.html
35
+ [userspace_configuration]: user_config_files.md
@@ -0,0 +1,117 @@
1
+ # State Storage
2
+
3
+ RBCli supports both local and remote state storage. This is done by synchronizing a Hash with either the local disk or a remote database.
4
+
5
+ ## Local State
6
+
7
+ RBCli's local state storage gives you access to a hash that is automatically persisted to disk when changes are made.
8
+
9
+ ### Configuration
10
+
11
+ You can configure it in `config/storage.rb`.
12
+
13
+ ```ruby
14
+ local_state '/var/mytool/localstate', force_creation: true, halt_on_error: true
15
+ ```
16
+
17
+ There are three parameters to configure it with:
18
+
19
+ * The `path` as a string (self-explanatory)
20
+ * `force_creation`
21
+ * This will attempt to create the path and file if it does not exist (equivalent to an `mkdir -p` and `touch` in linux)
22
+ * `halt_on_error`
23
+ * RBCli's default behavior is to raise an exception if the file can not be created, read, or updated at any point in time
24
+ * If this is set to `false`, RBCli will silence any errors pertaining to file access and will fall back to whatever data is available. Note that if this is enabled, changes made to the state may not be persisted to disk.
25
+ * If creation fails and file does not exist, you start with an empty hash
26
+ * If file exists but can't be read, you will have an empty hash
27
+ * If file can be read but not written, the hash will be populated with the data. Writes will be stored in memory while the application is running, but will not be persisted to disk.
28
+
29
+
30
+ ### Access and Usage
31
+
32
+ Once configured you can access it with a standard hash syntax in your Standard Commands:
33
+
34
+ ```ruby
35
+ Rbcli.local_state[:yourkeyhere]
36
+ ```
37
+
38
+ The methods available for use at the top level are as follows:
39
+
40
+ Hash native methods:
41
+
42
+ * `[]` (Regular hash syntax. Keys are accessed via either symbols or strings indifferently.)
43
+ * `[]=` (Assignment operator)
44
+ * `delete`
45
+ * `each`
46
+ * `key?`
47
+
48
+ Additional methods:
49
+
50
+ * `commit`
51
+ * Every assignment to the top level of the hash will result in a write to disk (for example: `Rbcli.local_state[:yourkey] = 'foo'`). However, if you are manipulating nested hashes, these saves will not be triggered. You can trigger them manually by calling `commit`.
52
+ * `clear`
53
+ * Resets the data back to an empty hash.
54
+ * `refresh`
55
+ * Loads the most current version of the data from the disk
56
+ * `disconnect`
57
+ * Removes the data from memory and sets `Rbcli.local_state = nil`. Data will be read from disk again on next access.
58
+
59
+
60
+ Every assignment will result in a write to disk, so if an operation will require a large number of assignments/writes it should be performed to a different hash before beign assigned to this one.
61
+
62
+
63
+ ## Remote State
64
+
65
+ RBCli's remote state storage gives you access to a hash that is automatically persisted to a remote storage location when changes are made. It has optional locking built-in, meaning that multiple users may share remote state without any data consistency issues.
66
+
67
+ Currently, this feature requires AWS DynamoDB, though other backend systems will be added in the future.
68
+
69
+ ### Configuration
70
+
71
+ Before DynamoDB can be used, AWS API credentials have to be created and made available. RBCli will attempt to find credentials from the following locations in order:
72
+
73
+ 1. User's config file
74
+ 2. Environment variables `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`
75
+ 3. User's AWSCLI configuration at `~/.aws/credentials`
76
+
77
+ For more information about generating and storing AWS credentials, see [Configuring the AWS SDK for Ruby][aws_sdk_credentials]. Please make sure that your users are aware that they will need to provide their own credentials to use this feature.
78
+
79
+ You can configure it in `config/storage.rb`.
80
+
81
+ ```ruby
82
+ remote_state_dynamodb table_name: 'mytable', region: 'us-east-1', force_creation: true, halt_on_error: true, locking: false
83
+ ```
84
+
85
+ These are the parameters:
86
+
87
+ * `table_name`
88
+ * The name of the DynamoDB table to use.
89
+ * `region`
90
+ * The AWS region that the database is located
91
+ * `force_creation`
92
+ * Creates the DynamoDB table if it does not already exist
93
+ * `halt_on_error`
94
+ * Similar to the way [Local State](#local-state) works, setting this to `false` will silence any errors in connecting to the DynamoDB table. Instead, your application will simply have access to an empty hash that does not get persisted anywhere.
95
+ * This is good for use cases that involve using this storage as a cache, where a connection error might mean the feature doesn't work but its not important enough to interrupt the user.
96
+ * `locking`
97
+ * Setting this to `true` enables locking, meaning only one instance of your application can access the shared data at any given time. For more information see [Distributed State Locking][distributed_state_locking].
98
+
99
+
100
+ ### Access and Usage
101
+
102
+ Once configured you can access it with a standard hash syntax:
103
+
104
+ ```ruby
105
+ Rbcli.remote_state[:yourkeyhere]
106
+ ```
107
+
108
+ This works the same way that [Local State](#local-state) does, with the same performance caveats (try not to write too frequently).
109
+
110
+ Note that all state in Rbcli is __lazy-loaded__, so no connections will be made until your code attempts to access the data even if the feature is enabled.
111
+
112
+ For more information on the available commands, see the documentation on [Local State](#local-state)
113
+
114
+
115
+ [aws_sdk_credentials]: https://docs.aws.amazon.com/sdk-for-ruby/v3/developer-guide/setup-config.html
116
+ [distributed_state_locking]: distributed_state_locking.md
117
+
@@ -0,0 +1,47 @@
1
+ # Configuration Files
2
+
3
+ RBCli provides built-in support for creating and managing userspace configuration files. It does this through two chains: the __defaults chain__ and the __user chain__.
4
+
5
+ ## Defaults chain
6
+
7
+ The defaults chain allows you to specify sane defaults for your CLI tool throughout your code. This gives you the ability to declare configuration alongside the code, and allows RBCli to generate a user config automatically given your defaults. There are two ways to set them:
8
+
9
+ * YAML Files
10
+ * You can store your defaults in one or more YAML files and RBCli will import and combine them. Note that when generating the user config, RBCli will use the YAML text as-is, so comments are transferred as well. This allows you to write descriptions for the options directly in the file that the user can see.
11
+ * This is good for tools with large or complex configuration that needs user documentation written inline
12
+ * These YAML files should be placed in the `userconf/` directory in your project and they will automatically be loaded
13
+ * DSL Statements
14
+ * In the DSL, you can specify options individually by providing a name, description, and default value
15
+ * This is good for simpler configuration, as the descriptions provided are written out as comments in the generated user config
16
+ * You can put global configuration options in `config/userspace.rb`
17
+ * Command-specific confiugration can be placed in the command declarations in `application/commands/*.rb`
18
+
19
+ DSL statements appear in both of the above locations as the following:
20
+
21
+ ```ruby
22
+ config_default :name, description: '<description_help_text>', default: '<default_value>'
23
+ ```
24
+ ## User chain
25
+
26
+ The user chain has two functions: generating and loading configuration from a YAML file on the end user's machine.
27
+
28
+ Rbcli will determine the correct location to locate the user configuration based on two factors:
29
+
30
+ 1. The default location set in `config/userspace.rb`
31
+ 2. The location specified on the command line using the `--config-file=<filename>` option (overrides #1)
32
+
33
+ To configure the default location, edit `config/userspace.rb`:
34
+
35
+ ```ruby
36
+ config_userfile '~/.mytool', merge_defaults: true, required: false
37
+ ```
38
+
39
+ * `path/to/config/file`
40
+ * Self explanatory. Recommended locations are a dotfile in the user's home directory, or a file under `/etc` such as `/etc/mytool/userconf.yaml`
41
+ * `merge_defaults`
42
+ * If set to `true`, user settings override default settings. If set to `false`, default settings are not loaded at all and the user is required to have all values specified in their config.
43
+ * `required`
44
+ * If set to `true` the application will not run if the file does not exist. A message will be displayed to the user to run your application with the `--generate-config` option to generate the file given your specified defaults.
45
+
46
+
47
+ Users can generate configs by running `yourclitool --generate-config`. This will generate a config file at the tool's default location specified in the DSL. This location can be overridden via the `--config-file=<filename>` option.
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at andrew@blacknex.us. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
@@ -0,0 +1,49 @@
1
+ # Contribution Guide
2
+
3
+ Contributing to RBCli is the same as most open source projects:
4
+
5
+ 1. Fork the repository
6
+ 2. Create your own branch
7
+ 3. Submit a pull request when ready
8
+
9
+ That's all there is to it! We've also kept our acceptance criteria pretty simple, as you'll see below. Feel free to submit a pull request even if you don't meet it if you would like your code or feature to be reviewed first; we do want to be mindful of your time and will review submissions before they are polished.
10
+
11
+ # Code Acceptance Criteria
12
+
13
+ ## Tabs, Not Spaces
14
+
15
+ Please, and thanks. We all like to use different indentation levels and styles, and this will keep us consistent between editors.
16
+
17
+ For filetypes where tabs are not supported (such as YAML), please stick to using two (2) spaces.
18
+
19
+ ## Documentation for User Features
20
+
21
+ For any modification that alters the way RBCli is used -- we're talking additional features, options, keyword changes, major behavioral changes, and the like -- the documentation will need to be updated as well. You'll be happy to know we designed it to make the process relatively painless.
22
+
23
+ RBCli's documentation is essentially a collection of markdown files that have been compiled into a static site using [MkDocs](https://www.mkdocs.org). If you already have python and pip on your system, you can install it by running:
24
+
25
+ ```bash
26
+ pip install mkdocs mkdocs-material
27
+ ```
28
+
29
+ You can find the source markdown files in the `docs-src/docs` folder, and the menu organization in `docs-src/mkdocs.yml`. To preview your changes on a live site, run:
30
+
31
+ ```bash
32
+ mkdocs serve
33
+ ```
34
+
35
+ Also, don't forget to update the __Quick Reference Guide__ in the `README.md` file (the main project one) with information about your changes.
36
+
37
+ Once you've completed your edits, run the `makesite.sh` command to build the actual HTML pages automatically in the `docs` folder, from where they will be served when live.
38
+
39
+ # Maintainer's Notes
40
+
41
+ To install this gem onto your local machine from source, run `bundle exec rake install`.
42
+
43
+ To release a new version, follow theese steps:
44
+
45
+ 1. Update the version number in `version.rb`
46
+ 2. Run `bundle exec rake install`, which will update `gemfile.lock` with the correct version and all dependency changes
47
+ 3. Run `docs-src/makesite.sh`, which re-compiles the documentation and pulls in the changelog and quick reference automatically
48
+ 4. Commit the above changes to master, but do not push
49
+ 5. Run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
@@ -0,0 +1,10 @@
1
+ # How RBCli is Licensed
2
+
3
+ We want to help the developer community build tooling faster and with less work. That's why RBCli was built. And let's face it - most of us aren't lawyers, and don't want to worry about legal fine print when building awesome software. That's why RBCli is released under the __GPLv3 License__. So you're free to use RBCli as you see fit to write free software. If you wish to use RBCli in a commercial offering, please contact me at [andrew@blacknex.us](mailto:andrew@blacknex.us).
4
+
5
+
6
+ # The License
7
+
8
+ You can view the offical license for RBCli [Here](https://github.com/akhoury6/rbcli/blob/master/LICENSE.txt).
9
+
10
+ For more details about the GPLv3 License, see [Here](https://choosealicense.com/licenses/gplv3/).
@@ -0,0 +1,31 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0 (Aug 5, 2018)
4
+
5
+ ### Features
6
+
7
+ * Official documentation created and hosted with Github Pages
8
+ * RBCli released under GPLv3
9
+ * Copyright/License notice displayed via RBCli tool with `rbcli license` in accordance with GPLv3 guidelines
10
+
11
+ ### Bugfixes
12
+
13
+ * Fixed version number loading for projects
14
+ * Cleaned up command usage help output
15
+ * Fixed script and external command generation
16
+
17
+ ### Improvements
18
+
19
+ * A quick reference guide can now be found in README.md
20
+ * CLI tool Autoupdate Enabled; when an upgrade to RBCli is detected, the RBCli CLI tool will notify the developer.
21
+ * Autoupdate feature now allows supplying a custom message
22
+ * Direct Path Mode for External Commands now
23
+ * Added support for a `lib` folder in projects, as a place for custom code, which is automatically added to `$LOAD_PATH` for developers
24
+ * Improved language regarding external commands: Documentation now differentiates between Standard, Scripted, and External Commands
25
+ * Improved language regarding user config files: Now called Userspace Config
26
+ * Options and Parameters now allow specifying the letter to be used for the short version, or to disable it altogether
27
+ * Userspace config can now be disabled by setting the path to nil or removing the declaration
28
+
29
+ ### Deprecations/Changes
30
+
31
+ * Removed deprecated and broken examples from the examples folder