toys-core 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,99 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "toys/middleware/base"
31
+
32
+ module Toys
33
+ module Middleware
34
+ ##
35
+ # A middleware that displays a version string for certain tools if the
36
+ # `--version` switch is given. You can specify which tools respond to
37
+ # this switch, and the string that will be displayed.
38
+ #
39
+ class ShowVersion < Base
40
+ ##
41
+ # Default version switches
42
+ # @return [Array<String>]
43
+ #
44
+ DEFAULT_VERSION_SWITCHES = ["--version"].freeze
45
+
46
+ ##
47
+ # Return a simple version displayer that returns the given string for
48
+ # the root tool.
49
+ #
50
+ # @return [Proc]
51
+ #
52
+ def self.root_version_displayer(version)
53
+ proc { |tool| tool.root? ? version : false }
54
+ end
55
+
56
+ ##
57
+ # Create a ShowVersion middleware
58
+ #
59
+ # @param [Proc] version_displayer A proc that takes a tool and returns
60
+ # either the version string that should be displayed, or a falsy
61
+ # value to indicate the tool should not have a `--version` switch.
62
+ # Defaults to a "null" displayer that returns false for all tools.
63
+ # @param [Array<String>] version_switches A list of switches that should
64
+ # trigger displaying the version. Default is
65
+ # {DEFAULT_VERSION_SWITCHES}.
66
+ #
67
+ def initialize(version_displayer: nil,
68
+ version_switches: DEFAULT_VERSION_SWITCHES)
69
+ @version_displayer = version_displayer || proc { |_| false }
70
+ @version_switches = version_switches
71
+ end
72
+
73
+ ##
74
+ # Adds the version switch if requested.
75
+ #
76
+ def config(tool)
77
+ version = @version_displayer.call(tool)
78
+ if version
79
+ tool.add_switch(:_show_version, *@version_switches,
80
+ doc: "Show version",
81
+ handler: ->(_val, _prev) { version },
82
+ only_unique: true)
83
+ end
84
+ yield
85
+ end
86
+
87
+ ##
88
+ # This middleware displays the version.
89
+ #
90
+ def execute(context)
91
+ if context[:_show_version]
92
+ puts context[:_show_version]
93
+ else
94
+ yield
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,123 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ module Toys
31
+ ##
32
+ # A template definition. Template classes should include this module.
33
+ #
34
+ # A template is a configurable set of DSL code that can be run in a toys
35
+ # configuration to automate tool defintion. For example, toys provides a
36
+ # "minitest" template that generates a "test" tool that invokes minitest.
37
+ # Templates will often support configuration; for example the minitest
38
+ # template lets you configure the paths to the test files.
39
+ #
40
+ # ## Usage
41
+ #
42
+ # To create a template, define a class and include this module.
43
+ # The class defines the "configuration" of the template. If your template
44
+ # has options/parameters, you should provide a constructor, and methods
45
+ # appropriate to edit those options. The arguments given to the
46
+ # {Toys::ConfigDSL#expand} method are passed to your constructor, and your
47
+ # template object is passed to any block given to {Toys::ConfigDSL#expand}.
48
+ #
49
+ # Next, in your template class, call the `to_expand` method, which is defined
50
+ # in {Toys::Template::ClassMethods#to_expand}. Pass this a block which
51
+ # defines the implementation of the template. Effectively, the contents of
52
+ # this block are "inserted" into the user's configuration. The template
53
+ # object is passed to the block so you have access to the template options.
54
+ #
55
+ # ## Example
56
+ #
57
+ # This is a simple template that generates a "hello" tool. The tool simply
58
+ # prints a `"Hello, #{name}!"` greeting. The name is set as a template
59
+ # option; it is defined when the template is expanded in a toys
60
+ # configuration.
61
+ #
62
+ # # Define a template by creating a class that includes Toys::Template.
63
+ # class MyHelloTemplate
64
+ # include Toys::Template
65
+ #
66
+ # # A user of the template may pass an optional name as a parameter to
67
+ # # `expand`, or leave it as the default of "world".
68
+ # def initialize(name: "world")
69
+ # @name = name
70
+ # end
71
+ #
72
+ # # The template is passed to the expand block, so a user of the
73
+ # # template may also call this method to set the name.
74
+ # attr_accessor :name
75
+ #
76
+ # # The following block is inserted when the template is expanded.
77
+ # to_expand do |template|
78
+ # desc "Prints a greeting to #{template.name}"
79
+ # tool "templated-greeting" do
80
+ # execute do
81
+ # puts "Hello, #{template.name}!"
82
+ # end
83
+ # end
84
+ # end
85
+ # end
86
+ #
87
+ # Now you can use the template in your `.toys.rb` file like this:
88
+ #
89
+ # expand(MyHelloTemplate, name: "rubyists")
90
+ #
91
+ # or alternately:
92
+ #
93
+ # expand(MyHelloTemplate) do |template|
94
+ # template.name = "rubyists"
95
+ # end
96
+ #
97
+ # And it will create a tool called "templated-greeting".
98
+ #
99
+ module Template
100
+ ## @private
101
+ def self.included(mod)
102
+ mod.extend(ClassMethods)
103
+ end
104
+
105
+ ##
106
+ # Class methods that will be added to a template class.
107
+ #
108
+ module ClassMethods
109
+ ##
110
+ # Provide the block that implements the template.
111
+ #
112
+ def to_expand(&block)
113
+ @expander = block
114
+ end
115
+
116
+ ##
117
+ # You may alternately set the expander block using this accessor.
118
+ # @return [Proc]
119
+ #
120
+ attr_accessor :expander
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,55 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "toys/utils/module_lookup"
31
+
32
+ module Toys
33
+ ##
34
+ # Namespace for common templates
35
+ #
36
+ module Templates
37
+ ##
38
+ # Return a template class by name.
39
+ #
40
+ # Currently recognized template names are:
41
+ #
42
+ # * `:clean` : Creates a tool that cleans build artifacts.
43
+ # * `:gem_build` : Creates a tool that builds and/or releases gems.
44
+ # * `:minitest` : Creates a tool that runs unit tests.
45
+ # * `:rubocop` : Creates a tool that runs rubocop.
46
+ # * `:yardoc` : Creates a tool that generates YARD documentation.
47
+ #
48
+ # @param [String,Symbol] name Name of the template class to return
49
+ # @return [Class,nil] The class, or `nil` if not found
50
+ #
51
+ def self.lookup(name)
52
+ Utils::ModuleLookup.lookup(:templates, name)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,82 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ module Toys
31
+ module Templates
32
+ ##
33
+ # A template for tools that clean build artifacts
34
+ #
35
+ class Clean
36
+ include Template
37
+
38
+ ##
39
+ # Default tool name
40
+ # @return [String]
41
+ #
42
+ DEFAULT_TOOL_NAME = "clean".freeze
43
+
44
+ ##
45
+ # Create the template settings for the Clean template.
46
+ #
47
+ # @param [String] name Name of the tool to create. Defaults to
48
+ # {DEFAULT_TOOL_NAME}.
49
+ # @param [Array<String>] paths An array of glob patterns indicating what
50
+ # to clean.
51
+ #
52
+ def initialize(name: DEFAULT_TOOL_NAME, paths: [])
53
+ @name = name
54
+ @paths = paths
55
+ end
56
+
57
+ attr_accessor :name
58
+ attr_accessor :paths
59
+
60
+ to_expand do |template|
61
+ tool(template.name) do
62
+ desc "Clean built files and directories."
63
+
64
+ use :file_utils
65
+
66
+ execute do
67
+ files = []
68
+ patterns = Array(template.paths)
69
+ patterns.each do |pattern|
70
+ files.concat(::Dir.glob(pattern))
71
+ end
72
+ files.uniq!
73
+
74
+ files.each do |file|
75
+ rm_rf file
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,121 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ require "rubygems/package"
31
+
32
+ module Toys
33
+ module Templates
34
+ ##
35
+ # A template for tools that build and release gems
36
+ #
37
+ class GemBuild
38
+ include Template
39
+
40
+ ##
41
+ # Default tool name
42
+ # @return [String]
43
+ #
44
+ DEFAULT_TOOL_NAME = "build".freeze
45
+
46
+ ##
47
+ # Create the template settings for the GemBuild template.
48
+ #
49
+ # @param [String] name Name of the tool to create. Defaults to
50
+ # {DEFAULT_TOOL_NAME}.
51
+ # @param [String] gem_name Name of the gem to build. If not provided,
52
+ # defaults to the first gemspec file it finds.
53
+ # @param [Boolean] push_gem If true, pushes the built gem to rubygems.
54
+ # @param [Boolean] tag If true, tags the git repo with the gem version.
55
+ # @param [Boolean,String] push_tag If truthy, pushes the new tag to
56
+ # a git remote. You may specify which remote by setting the value to
57
+ # a string. Otherwise, if the value is simply `true`, the "origin"
58
+ # remote is used by default.
59
+ #
60
+ def initialize(name: DEFAULT_TOOL_NAME,
61
+ gem_name: nil,
62
+ push_gem: false,
63
+ tag: false,
64
+ push_tag: false)
65
+ @name = name
66
+ @gem_name = gem_name
67
+ @push_gem = push_gem
68
+ @tag = tag
69
+ @push_tag = push_tag
70
+ end
71
+
72
+ attr_accessor :name
73
+ attr_accessor :gem_name
74
+ attr_accessor :push_gem
75
+ attr_accessor :tag
76
+ attr_accessor :push_tag
77
+
78
+ to_expand do |template|
79
+ unless template.gem_name
80
+ candidates = ::Dir.glob("*.gemspec")
81
+ if candidates.empty?
82
+ raise ToolDefinitionError, "Could not find a gemspec"
83
+ end
84
+ template.gem_name = candidates.first.sub(/\.gemspec$/, "")
85
+ end
86
+ task_type = template.push_gem ? "Release" : "Build"
87
+
88
+ tool(template.name) do
89
+ desc "#{task_type} the gem: #{template.gem_name}"
90
+
91
+ use :file_utils
92
+ use :exec
93
+
94
+ execute do
95
+ configure_exec(exit_on_nonzero_status: true)
96
+ gemspec = ::Gem::Specification.load "#{template.gem_name}.gemspec"
97
+ version = gemspec.version
98
+ gemfile = "#{template.gem_name}-#{version}.gem"
99
+ ::Gem::Package.build gemspec
100
+ mkdir_p "pkg"
101
+ mv gemfile, "pkg"
102
+ if template.push_gem
103
+ if ::File.directory?(".git") && capture("git status -s").strip != ""
104
+ logger.error "Cannot push the gem when there are uncommited changes"
105
+ exit(1)
106
+ end
107
+ sh "gem push pkg/#{gemfile}"
108
+ if template.tag
109
+ sh "git tag v#{version}"
110
+ if template.push_tag
111
+ template.push_tag = "origin" if template.push_tag == true
112
+ sh "git push #{template.push_tag} v#{version}"
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end