toys 0.12.2 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +35 -0
  4. data/LICENSE.md +1 -1
  5. data/README.md +7 -4
  6. data/builtins/system/git-cache.rb +238 -0
  7. data/builtins/system/test.rb +37 -2
  8. data/core-docs/toys/acceptor.rb +432 -0
  9. data/core-docs/toys/arg_parser.rb +397 -0
  10. data/core-docs/toys/cli.rb +493 -0
  11. data/core-docs/toys/compat.rb +2 -0
  12. data/core-docs/toys/completion.rb +329 -0
  13. data/core-docs/toys/context.rb +321 -0
  14. data/core-docs/toys/core.rb +14 -0
  15. data/core-docs/toys/dsl/base.rb +56 -0
  16. data/core-docs/toys/dsl/flag.rb +261 -0
  17. data/core-docs/toys/dsl/flag_group.rb +259 -0
  18. data/core-docs/toys/dsl/internal.rb +4 -0
  19. data/core-docs/toys/dsl/positional_arg.rb +139 -0
  20. data/core-docs/toys/dsl/tool.rb +1530 -0
  21. data/core-docs/toys/errors.rb +93 -0
  22. data/core-docs/toys/flag.rb +549 -0
  23. data/core-docs/toys/flag_group.rb +186 -0
  24. data/core-docs/toys/input_file.rb +8 -0
  25. data/core-docs/toys/loader.rb +222 -0
  26. data/core-docs/toys/middleware.rb +295 -0
  27. data/core-docs/toys/mixin.rb +142 -0
  28. data/core-docs/toys/module_lookup.rb +75 -0
  29. data/core-docs/toys/positional_arg.rb +145 -0
  30. data/core-docs/toys/settings.rb +507 -0
  31. data/core-docs/toys/source_info.rb +127 -0
  32. data/core-docs/toys/standard_middleware/add_verbosity_flags.rb +49 -0
  33. data/core-docs/toys/standard_middleware/apply_config.rb +24 -0
  34. data/core-docs/toys/standard_middleware/handle_usage_errors.rb +33 -0
  35. data/core-docs/toys/standard_middleware/set_default_descriptions.rb +222 -0
  36. data/core-docs/toys/standard_middleware/show_help.rb +190 -0
  37. data/core-docs/toys/standard_middleware/show_root_version.rb +45 -0
  38. data/core-docs/toys/standard_mixins/bundler.rb +83 -0
  39. data/core-docs/toys/standard_mixins/exec.rb +645 -0
  40. data/core-docs/toys/standard_mixins/fileutils.rb +18 -0
  41. data/core-docs/toys/standard_mixins/gems.rb +48 -0
  42. data/core-docs/toys/standard_mixins/git_cache.rb +41 -0
  43. data/core-docs/toys/standard_mixins/highline.rb +133 -0
  44. data/core-docs/toys/standard_mixins/terminal.rb +135 -0
  45. data/core-docs/toys/standard_mixins/xdg.rb +49 -0
  46. data/core-docs/toys/template.rb +112 -0
  47. data/core-docs/toys/tool_definition.rb +926 -0
  48. data/core-docs/toys/utils/completion_engine.rb +49 -0
  49. data/core-docs/toys/utils/exec.rb +721 -0
  50. data/core-docs/toys/utils/gems.rb +185 -0
  51. data/core-docs/toys/utils/git_cache.rb +353 -0
  52. data/core-docs/toys/utils/help_text.rb +134 -0
  53. data/core-docs/toys/utils/terminal.rb +310 -0
  54. data/core-docs/toys/utils/xdg.rb +253 -0
  55. data/core-docs/toys/wrappable_string.rb +120 -0
  56. data/core-docs/toys-core.rb +63 -0
  57. data/docs/guide.md +497 -156
  58. data/lib/toys/standard_cli.rb +50 -36
  59. data/lib/toys/templates/clean.rb +18 -0
  60. data/lib/toys/templates/gem_build.rb +24 -0
  61. data/lib/toys/templates/minitest.rb +21 -0
  62. data/lib/toys/templates/rake.rb +23 -3
  63. data/lib/toys/templates/rdoc.rb +29 -0
  64. data/lib/toys/templates/rspec.rb +32 -4
  65. data/lib/toys/templates/rubocop.rb +14 -1
  66. data/lib/toys/templates/yardoc.rb +55 -0
  67. data/lib/toys/testing.rb +186 -109
  68. data/lib/toys/version.rb +1 -1
  69. data/lib/toys.rb +4 -2
  70. metadata +56 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68fdda1df8ea614918dd8fadaf1e5766693b036cc06c737b4327d48e769d9b5b
4
- data.tar.gz: 73acd0ec7f1ae55e8ad18625246b0af9632a3e24423f669b0c06e03507f5e8fc
3
+ metadata.gz: db87e9639c06ca1247cc72180b8cab752962b86535089aebc8d97daa31b3a804
4
+ data.tar.gz: 6ca990bbc0010806cf57ab6ca2fd1cde84790bfa647ff6eb948c9b19f66b408b
5
5
  SHA512:
6
- metadata.gz: 9a97a0179a67317b43ff07e922aa81846375f4db1f5df1c9040c850e41a39d8521049369a4545e6e000ed7adda613c7b80c91d92bc3e30a46888bcac49f05fd5
7
- data.tar.gz: 7118fd3217f088ea41a8a7ea9bd063dece182cce2db5d0ae5d6e70850fe423ba757156a6f010a46ed0077ea5c5ab4748e0b222be1067c24be0f4e5ff22093e12
6
+ metadata.gz: 76c394b761f29c3d8891a2bdf527275bbf217c27bbc1e774eaef21fa79c8aa5b7327022f585c60fa4eae08af46216b3c466d52595662ee7f1a40465f0882df63
7
+ data.tar.gz: '0944f37779985979d90f86be071e6b53f2917f0a005363ea338f20dc993e4900218e864b7e6753f1a7222fed5077c2317e6e2727039496adcb877c9182817259'
data/.yardopts CHANGED
@@ -3,6 +3,8 @@
3
3
  --markup=markdown
4
4
  --markup-provider redcarpet
5
5
  --main=README.md
6
+ ./core-docs/toys/**/*.rb
7
+ ./core-docs/toys-core.rb
6
8
  ./lib/toys/**/*.rb
7
9
  ./lib/toys.rb
8
10
  -
data/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # Release History
2
2
 
3
+ ### v0.13.0 / 2022-02-08
4
+
5
+ Toys 0.13.0 is a major release with significant improvements to the testing framework and git cache, along with compatibility improvements and bug fixes.
6
+
7
+ Breaking changes:
8
+
9
+ * Passing `--directory=` to `toys system test` now restricts the search to *only* that directory, excluding global and builtin tools.
10
+ * Renamed `Toys::Testing#exec_tool` to `Toys::Testing#toys_exec_tool`.
11
+ * Removed the methods of `Toys::Testing` that were specific to "capture", "control", or "separate" spawning (i.e. `#exec_separate_tool`, `#capture_tool`, `#capture_separate_tool`, `#control_tool`, and `#control_separate_tool`). The general `Toys::Testing#toys_exec_tool` now either controls or captures depending on whether a block is present. Spawn-based execution is no longer available.
12
+
13
+ New functionality:
14
+
15
+ * Provided several builtin system tools for viewing and managing the git cache.
16
+ * The `load_git` directive and the underlying `Toys::Utils::GitCache` class now support updating from git based on cache age.
17
+ * The `Toys::Utils::GitCache` class supports supports copying git content into a provided directory, querying repo information, and deleting cache data.
18
+ * The `Toys::Utils::GitCache` class makes files read-only, to help prevent clients from interfering with one another.
19
+ * The `:terminal` mixin and the underlying `Toys::Utils::Terminal` class now honor the `NO_COLOR` environment variable.
20
+ * `toys system test` now understands `--minitest-focus` and `--minitest-rg` to activate those plugins.
21
+ * `toys system test` now understands `--minitest-version=` to set the minitest version requirement.
22
+ * Added `Toys::Testing#toys_run_tool` to run a tool in-process for testing.
23
+ * Added `Toys::Testing#toys_load_tool` to load a tool in-process and provide a way to test individual methods.
24
+ * Added `:custom_paths` and `:include_builtins` arguments to the `Toys::StandardCLI` constructor.
25
+
26
+ Fixes and compatibility:
27
+
28
+ * Bundler install/updates are now spawned in subprocesses for compatibility with bundler 2.3. The bundler integration also now requires bundler 2.2 or later.
29
+ * The `exec_tool` and `exec_proc` methods in the `:exec` mixin now log their execution in the same way as other exec functions.
30
+ * Minor compatibility fixes to provide partial support for TruffleRuby.
31
+
32
+ Other notes:
33
+
34
+ * The internal GitCache representation has changed significantly to support additional features and improve robustness and performance. This will force existing caches to update, but should not break existing usage.
35
+ * Significant updates to the readme and user guide, including a section in the user guide on the test framework.
36
+ * Toys-core docs are now embedded into the toys gem, so that all the links will work in rubydoc.info.
37
+
3
38
  ### v0.12.2 / 2021-08-30
4
39
 
5
40
  * FIXED: Tool context inspect string is no longer overwhelmingly long
data/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # License
2
2
 
3
- Copyright 2019-2020 Daniel Azuma and the Toys contributors
3
+ Copyright 2019-2022 Daniel Azuma and the Toys contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -55,6 +55,9 @@ Toys requires Ruby 2.4 or later.
55
55
  Most parts of Toys work on JRuby. However, JRuby is not recommended because of
56
56
  JVM boot latency, lack of support for Kernel#fork, and other issues.
57
57
 
58
+ Most parts of Toys work on TruffleRuby. However, TruffleRuby is not recommended
59
+ because it has a few known bugs that affect Toys.
60
+
58
61
  ### Write your first tool
59
62
 
60
63
  You can define tools by creating a *Toys file*. Go into any directory, and,
@@ -134,7 +137,7 @@ tool to the end of the file.)
134
137
  exec "git init"
135
138
  File.write ".gitignore", <<~CONTENT
136
139
  tmp
137
- .DS_STORE
140
+ .DS_Store
138
141
  CONTENT
139
142
  # You can add additional files here.
140
143
  exec "git add ."
@@ -279,8 +282,8 @@ and take advantage of a variety of third-party libraries such as Highline and
279
282
  TTY. Finally, if your `.toys.rb` files are growing too large or complicated,
280
283
  you can replace them with `.toys` directories that contain tool definitions in
281
284
  separate files. Such directories are versatile, letting you organize your tool
282
- definitions, along with shared code, normal Ruby classes, and even data files
283
- for use by tools.
285
+ definitions, along with shared code, normal Ruby classes, tests, and even data
286
+ files for use by tools.
284
287
 
285
288
  Unlike most command line frameworks, Toys is *not primarily* designed to help
286
289
  you build and ship a custom command line executable written in Ruby. However,
@@ -319,7 +322,7 @@ Toys scripts instead of Rakefiles.
319
322
 
320
323
  ## License
321
324
 
322
- Copyright 2019-2020 Daniel Azuma and the Toys contributors
325
+ Copyright 2019-2022 Daniel Azuma and the Toys contributors
323
326
 
324
327
  Permission is hereby granted, free of charge, to any person obtaining a copy
325
328
  of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,238 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc "Git-cache management tools"
4
+
5
+ long_desc \
6
+ "Tools that manage the git cache.",
7
+ "",
8
+ "The Toys::Utils::GitCache class manages a cache of files from remote git repoistories." \
9
+ " It is used when loading tools from git, and can also be used directly by tools to access" \
10
+ " files from a remote git repository such as from GitHub.",
11
+ "",
12
+ "The tools under the `system git-cache` namespace manage the contents of the git-cache," \
13
+ " including querying the cache, getting information about cache status, and removing old data."
14
+
15
+ tool "list" do
16
+ desc "Output a list of the git repositories in the cache."
17
+
18
+ long_desc \
19
+ "Outputs a list of the git remotes for the repositories in the cache, in YAML format, to" \
20
+ " the standard output stream."
21
+
22
+ flag :cache_dir, "--cache-dir=PATH" do
23
+ desc "The base directory for the cache. Optional. Defaults to the standard cache directory."
24
+ end
25
+
26
+ def run
27
+ require "psych"
28
+ require "toys/utils/git_cache"
29
+ git_cache = ::Toys::Utils::GitCache.new(cache_dir: cache_dir)
30
+ output = {
31
+ "cache_dir" => git_cache.cache_dir,
32
+ "remotes" => git_cache.remotes,
33
+ }
34
+ puts(::Psych.dump(output))
35
+ end
36
+ end
37
+
38
+ tool "show" do
39
+ desc "Output information about the specified git repo in the cache."
40
+
41
+ long_desc \
42
+ "Outputs information about the git repo specified by the given remote, in YAML format, to" \
43
+ " the standard output stream."
44
+
45
+ required_arg :remote, desc: "The git remote identifying the repo. Required."
46
+
47
+ flag :cache_dir, "--cache-dir=PATH" do
48
+ desc "The base directory for the cache. Optional. Defaults to the standard cache directory."
49
+ end
50
+
51
+ def run
52
+ require "psych"
53
+ require "toys/utils/git_cache"
54
+ git_cache = ::Toys::Utils::GitCache.new(cache_dir: cache_dir)
55
+ info = git_cache.repo_info(remote)
56
+ if info.nil?
57
+ logger.fatal("Unknown remote: #{remote}")
58
+ exit(1)
59
+ end
60
+ puts(::Psych.dump(info.to_h))
61
+ end
62
+ end
63
+
64
+ tool "get" do
65
+ desc "Get files from the git cache, loading from the repo if necessary."
66
+
67
+ long_desc \
68
+ "Get files from the git cache, loading from the repo if necessary, and output the path to" \
69
+ " the files to the standard output stream.",
70
+ "",
71
+ "The resulting files are either served from a shared source directory, or copied into aa" \
72
+ " directory specified by the `--into=` flag. If you use the shared directory, do not" \
73
+ " modify the files or directory structure, or other callers will see your modifications."
74
+
75
+ required_arg :remote, desc: "The git remote identifying the repo. Required."
76
+
77
+ flag :cache_dir, "--cache-dir=PATH" do
78
+ desc "The base directory for the cache. Optional. Defaults to the standard cache directory."
79
+ end
80
+
81
+ flag :path, "--path=PATH" do
82
+ desc "A path to a specific file or directory in the repository. Optional. Defaults to the" \
83
+ " entire repository."
84
+ end
85
+
86
+ flag :commit, "--commit=REF", "--ref=REF" do
87
+ desc "The commit, which may be a SHA, branch, tag, or HEAD (the default). Optional."
88
+ end
89
+
90
+ flag :update do
91
+ desc "Update refs, such as branches, from the remote repo."
92
+ end
93
+
94
+ flag :into, "--into=DIR" do
95
+ desc "Copy files into the given directory rather than returning a shared directory."
96
+ end
97
+
98
+ def run
99
+ require "toys/utils/git_cache"
100
+ git_cache = ::Toys::Utils::GitCache.new(cache_dir: cache_dir)
101
+ out = git_cache.get(remote, path: path, commit: commit, into: into, update: update)
102
+ puts(out)
103
+ rescue ::Toys::Utils::GitCache::Error => e
104
+ logger.fatal(e.message)
105
+ exit(1)
106
+ end
107
+ end
108
+
109
+ tool "remove" do
110
+ desc "Remove the given repositories from the cache."
111
+
112
+ long_desc \
113
+ "Remove the given repositories, including local clones and all shared source directories," \
114
+ " from the cache. The next time any of these repositories is requested, it will be" \
115
+ " reloaded from the remote repository from scratch.",
116
+ "",
117
+ "You can remove specific repositories by providing their remotes as arguments, or remove all" \
118
+ " repositories from the cache by specifying the `--all` flag.",
119
+ "",
120
+ "Be careful not to clear repos that are currently in use by other processes. This command" \
121
+ " may delete files that are in use by other git-cache clients."
122
+
123
+ remaining_args :remotes, desc: "The git remote(s) identifying the repo(s) to remove."
124
+
125
+ flag :cache_dir, "--cache-dir=PATH" do
126
+ desc "The base directory for the cache. Optional. Defaults to the standard cache directory."
127
+ end
128
+
129
+ flag :all do
130
+ desc "Remove all repositories. Required unless specific remotes are provided."
131
+ end
132
+
133
+ def run
134
+ require "psych"
135
+ require "toys/utils/git_cache"
136
+ if remotes.empty? == !all
137
+ logger.fatal("You must specify at least one remote to clear, or --all to clear all remotes.")
138
+ exit(2)
139
+ end
140
+ git_cache = ::Toys::Utils::GitCache.new(cache_dir: cache_dir)
141
+ removed = git_cache.remove_repos(all ? :all : remotes)
142
+ output = {
143
+ "removed" => removed,
144
+ }
145
+ puts(::Psych.dump(output))
146
+ end
147
+ end
148
+
149
+ tool "remove-refs" do
150
+ desc "Removes records of the given refs from the cache."
151
+
152
+ long_desc \
153
+ "Removes records of the given refs (i.e. branches, tags, or HEAD) from the cache for the" \
154
+ " given repo. The next time any of these refs are requested, they will be pulled fresh" \
155
+ " from the remote repo.",
156
+ "",
157
+ "You must provide either the `--all` flag to remove all refs, or at least one `--ref=` flag" \
158
+ " to remove specific refs.",
159
+ "",
160
+ "Outputs a list of the refs actually removed, in YAML format, to the standard output stream."
161
+
162
+ required_arg :remote, desc: "The git remote identifying the repo. Required."
163
+
164
+ exactly_one_required do
165
+ flag :refs, "--ref=REF", handler: :push do
166
+ desc "Remove a specific ref."
167
+ end
168
+
169
+ flag :all do
170
+ desc "Remove all refs."
171
+ end
172
+ end
173
+
174
+ flag :cache_dir, "--cache-dir=PATH" do
175
+ desc "The base directory for the cache. Optional. Defaults to the standard cache directory."
176
+ end
177
+
178
+ def run
179
+ require "psych"
180
+ require "toys/utils/git_cache"
181
+ git_cache = ::Toys::Utils::GitCache.new(cache_dir: cache_dir)
182
+ removed = git_cache.remove_refs(remote, refs: refs)
183
+ if removed.nil?
184
+ logger.fatal("Unknown remote: #{remote}")
185
+ exit(1)
186
+ end
187
+ output = {
188
+ "remote" => remote,
189
+ "removed_refs" => removed.map(&:to_h),
190
+ }
191
+ puts(::Psych.dump(output))
192
+ end
193
+ end
194
+
195
+ tool "remove-sources" do
196
+ desc "Removes shared sources from the cache."
197
+
198
+ long_desc \
199
+ "Removes the specified shared sources from the cache for the given repository. The next time" \
200
+ " these files are retrieved, they will be recopied from the repository.",
201
+ "",
202
+ "You must provide either the `--all` flag to remove all sources associated with the repo," \
203
+ " or at least one `--commit=` flag to remove sources for specific commits.",
204
+ "",
205
+ "Outputs a list of the sources actually removed, in YAML format, to the standard output stream."
206
+
207
+ required_arg :remote, desc: "The git remote identifying the repo. Required."
208
+
209
+ exactly_one_required do
210
+ flag :commits, "--commit=REF", handler: :push do
211
+ desc "Remove sources associated with a specific commit."
212
+ end
213
+
214
+ flag :all do
215
+ desc "Remove all sources."
216
+ end
217
+ end
218
+
219
+ flag :cache_dir, "--cache-dir=PATH" do
220
+ desc "The base directory for the cache. Optional. Defaults to the standard cache directory."
221
+ end
222
+
223
+ def run
224
+ require "psych"
225
+ require "toys/utils/git_cache"
226
+ git_cache = ::Toys::Utils::GitCache.new(cache_dir: cache_dir)
227
+ removed = git_cache.remove_sources(remote, commits: commits)
228
+ if removed.nil?
229
+ logger.fatal("Unknown remote: #{remote}")
230
+ exit(1)
231
+ end
232
+ output = {
233
+ "remote" => remote,
234
+ "removed_sources" => removed.map(&:to_h),
235
+ }
236
+ puts(::Psych.dump(output))
237
+ end
238
+ end
@@ -17,20 +17,40 @@ flag :recursive, "--[no-]recursive", default: true,
17
17
  desc: "Recursively test subtools (default is true)"
18
18
  flag :tool, "-t TOOL", "--tool TOOL", default: "",
19
19
  desc: "Run tests only for tools under the given path"
20
+ flag :minitest_version, "--minitest-version=VERSION", default: "~> 5.0",
21
+ desc: "Set the minitest version requirement (default is ~>5.0)"
22
+ flag :minitest_focus, "--minitest-focus[=VERSION]",
23
+ desc: "Make minitest-focus available during the run"
24
+ flag :minitest_rg, "--minitest-rg[=VERSION]",
25
+ desc: "Make minitest-rg available during the run"
20
26
 
21
27
  include :exec
22
28
  include :gems
23
29
  include :terminal
24
30
 
25
31
  def run
26
- gem "minitest", "~> 5.0"
32
+ load_minitest_gems
27
33
  ::Dir.chdir(tool_dir)
28
34
  test_files = find_test_files
29
35
  result = exec_ruby(ruby_args, in: :controller, log_cmd: "Starting minitest...") do |controller|
30
- controller.in.puts("gem 'minitest', '~> 5.0'")
36
+ controller.in.puts("gem 'minitest', '= #{::Minitest::VERSION}'")
31
37
  controller.in.puts("require 'minitest/autorun'")
38
+ if minitest_focus
39
+ controller.in.puts("gem 'minitest-focus', '= #{::Minitest::Test::Focus::VERSION}'")
40
+ controller.in.puts("require 'minitest/focus'")
41
+ end
42
+ if minitest_rg
43
+ controller.in.puts("gem 'minitest-rg', '= #{::MiniTest::RG::VERSION}'")
44
+ controller.in.puts("require 'minitest/rg'")
45
+ end
46
+ controller.in.puts("gem 'toys', '= #{::Toys::VERSION}'")
32
47
  controller.in.puts("require 'toys'")
33
48
  controller.in.puts("require 'toys/testing'")
49
+ if directory
50
+ dir_str = ::File.absolute_path(directory).inspect
51
+ controller.in.puts("Toys::Testing.toys_custom_paths(#{dir_str})")
52
+ controller.in.puts("Toys::Testing.toys_include_builtins(false)")
53
+ end
34
54
  test_files.each do |file|
35
55
  controller.in.puts("load '#{file}'")
36
56
  end
@@ -41,6 +61,21 @@ def run
41
61
  end
42
62
  end
43
63
 
64
+ def load_minitest_gems
65
+ gem "minitest", minitest_version
66
+ require "minitest"
67
+ if minitest_focus
68
+ minitest_focus = "~> 1.0" if minitest_focus == true
69
+ gem "minitest-focus", minitest_focus
70
+ require "minitest/focus"
71
+ end
72
+ if minitest_rg
73
+ minitest_rg = "~> 5.0" if minitest_rg == true
74
+ gem "minitest-rg", minitest_rg
75
+ require "minitest/rg"
76
+ end
77
+ end
78
+
44
79
  def find_test_files
45
80
  glob = ".test/**/test_*.rb"
46
81
  glob = "**/#{glob}" if recursive