toys 0.11.5 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +71 -0
  4. data/LICENSE.md +1 -1
  5. data/README.md +8 -5
  6. data/builtins/system/bash-completion.rb +89 -0
  7. data/builtins/system/git-cache.rb +238 -0
  8. data/builtins/system/test.rb +131 -0
  9. data/builtins/system/update.rb +48 -0
  10. data/core-docs/toys/acceptor.rb +432 -0
  11. data/core-docs/toys/arg_parser.rb +397 -0
  12. data/core-docs/toys/cli.rb +493 -0
  13. data/core-docs/toys/compat.rb +2 -0
  14. data/core-docs/toys/completion.rb +329 -0
  15. data/core-docs/toys/context.rb +321 -0
  16. data/core-docs/toys/core.rb +14 -0
  17. data/core-docs/toys/dsl/base.rb +56 -0
  18. data/core-docs/toys/dsl/flag.rb +261 -0
  19. data/core-docs/toys/dsl/flag_group.rb +259 -0
  20. data/core-docs/toys/dsl/internal.rb +4 -0
  21. data/core-docs/toys/dsl/positional_arg.rb +139 -0
  22. data/core-docs/toys/dsl/tool.rb +1530 -0
  23. data/core-docs/toys/errors.rb +93 -0
  24. data/core-docs/toys/flag.rb +549 -0
  25. data/core-docs/toys/flag_group.rb +186 -0
  26. data/core-docs/toys/input_file.rb +8 -0
  27. data/core-docs/toys/loader.rb +222 -0
  28. data/core-docs/toys/middleware.rb +295 -0
  29. data/core-docs/toys/mixin.rb +142 -0
  30. data/core-docs/toys/module_lookup.rb +75 -0
  31. data/core-docs/toys/positional_arg.rb +145 -0
  32. data/core-docs/toys/settings.rb +507 -0
  33. data/core-docs/toys/source_info.rb +127 -0
  34. data/core-docs/toys/standard_middleware/add_verbosity_flags.rb +49 -0
  35. data/core-docs/toys/standard_middleware/apply_config.rb +24 -0
  36. data/core-docs/toys/standard_middleware/handle_usage_errors.rb +33 -0
  37. data/core-docs/toys/standard_middleware/set_default_descriptions.rb +222 -0
  38. data/core-docs/toys/standard_middleware/show_help.rb +190 -0
  39. data/core-docs/toys/standard_middleware/show_root_version.rb +45 -0
  40. data/core-docs/toys/standard_mixins/bundler.rb +83 -0
  41. data/core-docs/toys/standard_mixins/exec.rb +645 -0
  42. data/core-docs/toys/standard_mixins/fileutils.rb +18 -0
  43. data/core-docs/toys/standard_mixins/gems.rb +48 -0
  44. data/core-docs/toys/standard_mixins/git_cache.rb +41 -0
  45. data/core-docs/toys/standard_mixins/highline.rb +133 -0
  46. data/core-docs/toys/standard_mixins/terminal.rb +135 -0
  47. data/core-docs/toys/standard_mixins/xdg.rb +49 -0
  48. data/core-docs/toys/template.rb +112 -0
  49. data/core-docs/toys/tool_definition.rb +926 -0
  50. data/core-docs/toys/utils/completion_engine.rb +49 -0
  51. data/core-docs/toys/utils/exec.rb +721 -0
  52. data/core-docs/toys/utils/gems.rb +185 -0
  53. data/core-docs/toys/utils/git_cache.rb +353 -0
  54. data/core-docs/toys/utils/help_text.rb +134 -0
  55. data/core-docs/toys/utils/terminal.rb +310 -0
  56. data/core-docs/toys/utils/xdg.rb +253 -0
  57. data/core-docs/toys/wrappable_string.rb +120 -0
  58. data/core-docs/toys-core.rb +63 -0
  59. data/docs/guide.md +588 -159
  60. data/lib/toys/standard_cli.rb +50 -39
  61. data/lib/toys/templates/clean.rb +35 -1
  62. data/lib/toys/templates/gem_build.rb +46 -4
  63. data/lib/toys/templates/minitest.rb +38 -1
  64. data/lib/toys/templates/rake.rb +41 -5
  65. data/lib/toys/templates/rdoc.rb +51 -3
  66. data/lib/toys/templates/rspec.rb +49 -5
  67. data/lib/toys/templates/rubocop.rb +36 -4
  68. data/lib/toys/templates/yardoc.rb +85 -10
  69. data/lib/toys/testing.rb +274 -0
  70. data/lib/toys/version.rb +1 -1
  71. data/lib/toys.rb +4 -2
  72. metadata +62 -9
  73. data/builtins/system.rb +0 -152
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 063c28a7b9b7d3bc5f7ada761beb8623ff144b92847f2a9424889ca953d27cee
4
- data.tar.gz: a1bcdb384d7592a0a43760aab7cd6da0e4afa4b6a1fd1ad59bb74ed6a6eeef73
3
+ metadata.gz: db87e9639c06ca1247cc72180b8cab752962b86535089aebc8d97daa31b3a804
4
+ data.tar.gz: 6ca990bbc0010806cf57ab6ca2fd1cde84790bfa647ff6eb948c9b19f66b408b
5
5
  SHA512:
6
- metadata.gz: 50596ee8741422c0e186c7c2b63b52410a0afa1de04dfbea43e06acbf52c8b56f46c54c86471a80bae451c004d238ea94b58d666e7c39742de80bf9c95f95106
7
- data.tar.gz: 1230cf4acb2414f378be58279a3017cd897a101a7c715e4db88394a8490fdb46dee7d0d9a617196698c034dddf3c6ac88b3855ba19262785dd4989dcf253d409
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,76 @@
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
+
38
+ ### v0.12.2 / 2021-08-30
39
+
40
+ * FIXED: Tool context inspect string is no longer overwhelmingly long
41
+ * FIXED: Fixed an exception in GitCache and load_git when updating a changed ref
42
+
43
+ ### v0.12.1 / 2021-08-17
44
+
45
+ * FIXED: Fixed a regression in 0.12.0 where bundler could use the wrong Gemfile if you set a custom context directory
46
+
47
+ ### v0.12.0 / 2021-08-05
48
+
49
+ Toys 0.12.0 is a major release with significant new features and bug fixes, and a few minor breaking changes. Additionally, this release now requires Ruby 2.4 or later.
50
+
51
+ Breaking changes:
52
+
53
+ * Defining a tool with whitespace, control characters, or certain punctuation in the name, now raises ToolDefinitionError.
54
+ * The Toys::Tool class (for the object returned by the Toys::Context::Key::TOOL attribute) has been renamed to Toys::ToolDefinition so that the old name can be used for class-based tool definition.
55
+
56
+ New functionality:
57
+
58
+ * The DSL now supports a class-based tool definition syntax (in addition to the existing block-based syntax). Some users may prefer this new class-based style as more Ruby-like.
59
+ * The subtool list on help screens is now split into sections by source directory
60
+ * You can now load tools from a remote git repository using the load_git directive.
61
+ * Whitespace is now automatically considered a name delimiter when defining tools.
62
+ * There is experimental support for providing tests for tools.
63
+ * There is now an extensible settings mechanism to activate less-common tool behavior. Currently there is one setting, which causes subtools to inherit their parent's methods by default.
64
+ * The load directive can load into a new tool.
65
+ * You can now set the context directory individually for the standard build tools.
66
+ * Added a new standard mixin that provides XDG Base Directory information.
67
+ * Added a new standard mixin that provides cached access to remote git repos.
68
+
69
+ Fixes:
70
+
71
+ * Fixed some bundler integration issues that occurred when the bundle is being installed in a separate path such as a vendor directory.
72
+ * Exceptions raised from internal classes now include the full backtrace.
73
+
3
74
  ### v0.11.5 / 2021-03-28
4
75
 
5
76
  * BREAKING CHANGE: The exit_on_nonzero_status option to exec now exits on signals and failures to spawn, in addition to error codes.
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
@@ -50,11 +50,14 @@ Toys does not yet specially implement tab completion for zsh or other shells.
50
50
  However, if you are using zsh, installing bash completion using `bashcompinit`
51
51
  *mostly* works.
52
52
 
53
- Toys requires Ruby 2.3 or later.
53
+ Toys requires Ruby 2.4 or later.
54
54
 
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,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc "Bash tab completion for Toys"
4
+
5
+ long_desc \
6
+ "Tools that manage tab completion for Toys in the bash shell.",
7
+ "",
8
+ "To install tab completion for Toys, execute the following line in a bash shell, or" \
9
+ " include it in an init file such as your .bashrc:",
10
+ [" $(toys system bash-completion install)"],
11
+ "",
12
+ "To remove tab completion, execute:",
13
+ [" $(toys system bash-completion remove)"],
14
+ "",
15
+ "It is also possible to install completions for different executable names if you have" \
16
+ " aliases for Toys. See the help for the \"install\" and \"remove\" tools for details.",
17
+ "",
18
+ "The \"eval\" tool is the actual completion command invoked by bash when it needs to" \
19
+ " complete a toys command line. You shouldn't need to invoke it directly."
20
+
21
+ tool "eval" do
22
+ desc "Tab completion command (executed by bash)"
23
+
24
+ long_desc \
25
+ "Completion command invoked by bash to compete a toys command line. Generally you do not" \
26
+ " need to invoke this directly. It reads the command line context from the COMP_LINE" \
27
+ " and COMP_POINT environment variables, and outputs completion candidates to stdout."
28
+
29
+ disable_argument_parsing
30
+
31
+ def run
32
+ require "toys/utils/completion_engine"
33
+ result = ::Toys::Utils::CompletionEngine::Bash.new(cli).run
34
+ if result > 1
35
+ logger.fatal("This tool must be invoked as a bash completion command.")
36
+ end
37
+ exit(result)
38
+ end
39
+ end
40
+
41
+ tool "install" do
42
+ desc "Install bash tab completion"
43
+
44
+ long_desc \
45
+ "Outputs a command to set up Toys tab completion in the current bash shell.",
46
+ "",
47
+ "To use, execute the following line in a bash shell, or include it in an init file" \
48
+ " such as your .bashrc:",
49
+ [" $(toys system bash-completion install)"],
50
+ "",
51
+ "This will associate the toys tab completion logic with the `toys` executable by default." \
52
+ " If you have aliases for the toys executable, pass them as arguments. e.g.",
53
+ [" $(toys system bash-completion install my-toys-alias another-alias)"]
54
+
55
+ remaining_args :executable_names,
56
+ desc: "Names of executables for which to set up tab completion" \
57
+ " (default: #{::Toys::StandardCLI::EXECUTABLE_NAME})"
58
+
59
+ def run
60
+ require "shellwords"
61
+ path = ::File.join(::File.dirname(::File.dirname(__dir__)), "share", "bash-completion.sh")
62
+ exes = executable_names.empty? ? [::Toys::StandardCLI::EXECUTABLE_NAME] : executable_names
63
+ puts Shellwords.join(["source", path] + exes)
64
+ end
65
+ end
66
+
67
+ tool "remove" do
68
+ desc "Remove bash tab completion"
69
+
70
+ long_desc \
71
+ "Outputs a command to remove Toys tab completion from the current bash shell.",
72
+ "",
73
+ "To use, execute the following line in a bash shell:",
74
+ [" $(toys system bash-completion remove)"],
75
+ "",
76
+ "If you have other names or aliases for the toys executable, pass them as arguments. e.g.",
77
+ [" $(toys system bash-completion remove my-toys-alias another-alias)"]
78
+
79
+ remaining_args :executable_names,
80
+ desc: "Names of executables for which to set up tab completion" \
81
+ " (default: #{::Toys::StandardCLI::EXECUTABLE_NAME})"
82
+
83
+ def run
84
+ require "shellwords"
85
+ path = ::File.join(::File.dirname(::File.dirname(__dir__)), "share", "bash-completion-remove.sh")
86
+ exes = executable_names.empty? ? [::Toys::StandardCLI::EXECUTABLE_NAME] : executable_names
87
+ puts Shellwords.join(["source", path] + exes)
88
+ end
89
+ end
@@ -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
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc "Run tool tests"
4
+
5
+ flag :directory, "-d", "--directory PATH",
6
+ desc: "Run tests from the given directory"
7
+ flag :seed, "-s", "--seed SEED",
8
+ desc: "Sets random seed."
9
+ flag :warnings, "-w", "--[no-]warnings",
10
+ default: true,
11
+ desc: "Turn on Ruby warnings (defaults to true)"
12
+ flag :name, "-n", "--name PATTERN",
13
+ desc: "Filter run on /regexp/ or string."
14
+ flag :exclude, "-e", "--exclude PATTERN",
15
+ desc: "Exclude /regexp/ or string from run."
16
+ flag :recursive, "--[no-]recursive", default: true,
17
+ desc: "Recursively test subtools (default is true)"
18
+ flag :tool, "-t TOOL", "--tool TOOL", default: "",
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"
26
+
27
+ include :exec
28
+ include :gems
29
+ include :terminal
30
+
31
+ def run
32
+ load_minitest_gems
33
+ ::Dir.chdir(tool_dir)
34
+ test_files = find_test_files
35
+ result = exec_ruby(ruby_args, in: :controller, log_cmd: "Starting minitest...") do |controller|
36
+ controller.in.puts("gem 'minitest', '= #{::Minitest::VERSION}'")
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}'")
47
+ controller.in.puts("require 'toys'")
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
54
+ test_files.each do |file|
55
+ controller.in.puts("load '#{file}'")
56
+ end
57
+ end
58
+ if result.error?
59
+ logger.error("Minitest failed!")
60
+ exit(result.exit_code)
61
+ end
62
+ end
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
+
79
+ def find_test_files
80
+ glob = ".test/**/test_*.rb"
81
+ glob = "**/#{glob}" if recursive
82
+ test_files = ::Dir.glob(glob)
83
+ if test_files.empty?
84
+ logger.warn("No test files found")
85
+ exit
86
+ end
87
+ test_files.each do |file|
88
+ logger.info("Loading: #{file}")
89
+ end
90
+ test_files
91
+ end
92
+
93
+ def tool_dir
94
+ words = cli.loader.split_path(tool)
95
+ dir = base_dir
96
+ unless words.empty?
97
+ dir = ::File.join(dir, *words)
98
+ unless ::File.directory?(dir)
99
+ logger.warn("No such directory: #{dir}")
100
+ exit
101
+ end
102
+ end
103
+ dir
104
+ end
105
+
106
+ def base_dir
107
+ return ::File.absolute_path(directory) if directory
108
+ dir = ::Dir.getwd
109
+ loop do
110
+ candidate = ::File.join(dir, ::Toys::StandardCLI::CONFIG_DIR_NAME)
111
+ return candidate if ::File.directory?(candidate)
112
+ parent = ::File.dirname(dir)
113
+ if parent == dir
114
+ logger.error("Unable to find a Toys directory")
115
+ exit(1)
116
+ end
117
+ dir = parent
118
+ end
119
+ end
120
+
121
+ def ruby_args
122
+ args = []
123
+ args << "-w" if warnings
124
+ args << "-I#{::Toys::CORE_LIB_PATH}#{::File::PATH_SEPARATOR}#{::Toys::LIB_PATH}"
125
+ args << "-"
126
+ args << "--seed" << seed if seed
127
+ args << "--verbose" if verbosity.positive?
128
+ args << "--name" << name if name
129
+ args << "--exclude" << exclude if exclude
130
+ args
131
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ desc "Update Toys if a newer version is available"
4
+
5
+ long_desc "Checks rubygems for a newer version of Toys. If one is available, downloads" \
6
+ " and installs it."
7
+
8
+ flag :yes, "-y", "--yes", desc: "Do not ask for interactive confirmation"
9
+
10
+ include :exec
11
+ include :terminal
12
+
13
+ def run
14
+ require "rubygems"
15
+ configure_exec(exit_on_nonzero_status: true)
16
+ version_info = spinner(leading_text: "Checking rubygems for the latest release... ",
17
+ final_text: "Done.\n") do
18
+ capture(["gem", "list", "-q", "-r", "-e", "toys"])
19
+ end
20
+ if version_info =~ /toys\s\((.+)\)/
21
+ latest_version = ::Gem::Version.new(::Regexp.last_match(1))
22
+ cur_version = ::Gem::Version.new(::Toys::VERSION)
23
+ if latest_version > cur_version
24
+ prompt = "Update Toys from #{cur_version} to #{latest_version}? "
25
+ exit(1) unless yes || confirm(prompt, default: true)
26
+ result = spinner(leading_text: "Installing Toys version #{latest_version}... ",
27
+ final_text: "Done.\n") do
28
+ exec(["gem", "install", "toys", "--version", latest_version.to_s],
29
+ out: :capture, err: :capture)
30
+ end
31
+ if result.error?
32
+ puts(result.captured_out + result.captured_err)
33
+ puts("Toys failed to install version #{latest_version}", :red, :bold)
34
+ exit(1)
35
+ end
36
+ puts("Toys successfully installed version #{latest_version}", :green, :bold)
37
+ elsif latest_version < cur_version
38
+ puts("Toys is already at experimental version #{cur_version}, which is later than" \
39
+ " the latest released version #{latest_version}",
40
+ :yellow, :bold)
41
+ else
42
+ puts("Toys is already at the latest version: #{latest_version}", :green, :bold)
43
+ end
44
+ else
45
+ puts("Could not get latest Toys version", :red, :bold)
46
+ exit(1)
47
+ end
48
+ end