From aea280cdb84838bcebb66fbd16fc029620491cd9 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sun, 9 Jul 2017 12:20:46 +1200 Subject: [PATCH] Configuration can expose a list of targets for various tasks, notably create and build. --- lib/teapot/command/build.rb | 11 +++++++- lib/teapot/command/create.rb | 22 ++++++++-------- lib/teapot/configuration.rb | 18 +++++++++++-- lib/teapot/context.rb | 6 ++--- spec/teapot/command_spec.rb | 11 ++++---- spec/teapot/configuration_spec.rb | 43 +++++++++++++++++++++++++++++++ teapot.gemspec | 2 +- 7 files changed, 89 insertions(+), 24 deletions(-) create mode 100644 spec/teapot/configuration_spec.rb diff --git a/lib/teapot/command/build.rb b/lib/teapot/command/build.rb index 865a791..cf0818f 100644 --- a/lib/teapot/command/build.rb +++ b/lib/teapot/command/build.rb @@ -39,10 +39,19 @@ class Build < Samovar::Command many :targets, "Build these targets, or use them to help the dependency resolution process." split :argv, "Arguments passed to child process(es) of build if any." + # The targets to build: + def dependency_names(context) + if @targets.any? + @targets + else + context.configuration.targets[:build] + end + end + def invoke(parent) context = parent.context - chain = context.dependency_chain(@targets, context.configuration) + chain = context.dependency_chain(dependency_names(context), context.configuration) ordered = chain.ordered diff --git a/lib/teapot/command/create.rb b/lib/teapot/command/create.rb index a502c96..3643210 100644 --- a/lib/teapot/command/create.rb +++ b/lib/teapot/command/create.rb @@ -29,18 +29,10 @@ module Command class Create < Samovar::Command self.description = "Create a new teapot package using the specified repository." - options do - option "-t/--target-name ", "The target to use to create the project", default: 'Generate/Project/Initial' - end - one :project_name, "The name of the new project in title-case, e.g. 'My Project'." one :source, "The source repository to use for fetching packages, e.g. https://github.com/kurocha." many :packages, "Any additional packages you'd like to include in the project." - def target_name - @options[:target_name] - end - def invoke(parent) logger = parent.logger @@ -64,14 +56,22 @@ def invoke(parent) context = nested.context - Build[target_name, *@packages, '--', project_name].invoke(nested) + # The targets to build to create the initial project: + target_names = context.configuration.targets[:create] - # Fetch any additional packages: - Fetch[].invoke(nested) + if target_names.any? + # Generate the initial project files: + Build[*target_names, '--', project_name].invoke(nested) + + # Fetch any additional packages: + Fetch[].invoke(nested) + end + # Stage all files: index = repository.index index.add_all + # Commit the initial project files: Rugged::Commit.create(repository, tree: index.write_tree(repository), message: "Initial project files.", diff --git a/lib/teapot/configuration.rb b/lib/teapot/configuration.rb index 1176309..add5973 100755 --- a/lib/teapot/configuration.rb +++ b/lib/teapot/configuration.rb @@ -48,6 +48,9 @@ def initialize(context, package, name, packages = [], options = nil) @imports = IdentitySet.new @visibility = :private + + # A list of named targets for specific purposes: + @targets = Hash.new{|hash,key| hash[key] = Array.new} end def freeze @@ -56,6 +59,8 @@ def freeze @imports.freeze @visibility.freeze + @targets.freeze + super end @@ -70,6 +75,9 @@ def public! @visibility = :public end + # A table of named targets for specific purposes. + attr :targets + # Options used to bind packages to this configuration. attr :options @@ -178,7 +186,7 @@ def materialize # Mark this as resolved imported << import - updated = self.merge(named_configuration, import.options) || updated + updated = self.update(named_configuration, import.options) || updated else # It couldn't be resolved and hasn't already been resolved... @imports << import @@ -190,7 +198,7 @@ def materialize end # Merge an external configuration into this configuration. We won't override already defined packages. - def merge(configuration, options) + def update(configuration, options) updated = false configuration.packages.each do |external_package| @@ -214,6 +222,12 @@ def merge(configuration, options) end end + configuration.targets.each do |key, value| + @targets[key] += value + + updated = true + end + return updated end diff --git a/lib/teapot/context.rb b/lib/teapot/context.rb index 24e02cc..8b00447 100644 --- a/lib/teapot/context.rb +++ b/lib/teapot/context.rb @@ -44,7 +44,7 @@ def self.check(definition, definitions) # A context represents a specific root package instance with a given configuration and all related definitions. # A context is stateful in the sense that package selection is specialized based on #select and #dependency_chain. These parameters are usually set up initially as part of the context setup. class Context - def initialize(root, options = {}) + def initialize(root, **options) @root = Path[root] @options = options @@ -58,9 +58,7 @@ def initialize(root, options = {}) @loaded = {} - unless options[:fake] - load_root_package(options) - end + load_root_package(options) unless options[:load_root] == false end attr :root diff --git a/spec/teapot/command_spec.rb b/spec/teapot/command_spec.rb index 64695ef..1fb9d73 100644 --- a/spec/teapot/command_spec.rb +++ b/spec/teapot/command_spec.rb @@ -21,15 +21,16 @@ require 'teapot/command' RSpec.describe Teapot::Command, order: :defined do - let!(:source) {"https://github.com/kurocha"} - let!(:root) {Build::Files::Path.new(__dir__) + "command_spec"} - let!(:project_name) {"Test Project"} - let!(:project_path) {root + 'test-project'} + let(:source) {"https://github.com/kurocha"} + # let(:source) {File.expand_path("../../../../kurocha", __dir__)} + let(:root) {Build::Files::Path.new(__dir__) + "command_spec"} + let(:project_name) {"Test Project"} + let(:project_path) {root + 'test-project'} let(:top) {Teapot::Command::Top["--root", project_path.to_s]} context Teapot::Command::Create do - subject {top["create", project_name, source.to_s, "project"]} + subject {top["create", project_name, source.to_s, "generate-project"]} it "should create a new project" do root.delete diff --git a/spec/teapot/configuration_spec.rb b/spec/teapot/configuration_spec.rb new file mode 100644 index 0000000..1e64009 --- /dev/null +++ b/spec/teapot/configuration_spec.rb @@ -0,0 +1,43 @@ +# Copyright, 2016, by Samuel G. D. Williams. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +require 'teapot/context' +require 'teapot/configuration' + +RSpec.describe Teapot::Configuration do + let(:root) {Build::Files::Path[__dir__] + 'configuration_spec'} + + let(:context) {Teapot::Context.new(root, load_root: false)} + let(:master) {Teapot::Configuration.new(context, Teapot::Package.new(root + 'master', 'master'), 'master')} + let(:embedded) {Teapot::Configuration.new(context, Teapot::Package.new(root + 'embedded', 'embedded'), 'embedded')} + + context "with create targets" do + before(:each) do + master.targets[:create] << "hello" + embedded.targets[:create] << "world" + end + + it "can merge packages" do + expect(master.update(embedded, {})).to be_truthy + + expect(master.targets[:create]).to be == ["hello", "world"] + end + end +end diff --git a/teapot.gemspec b/teapot.gemspec index f536e85..c65b50d 100644 --- a/teapot.gemspec +++ b/teapot.gemspec @@ -38,7 +38,7 @@ Gem::Specification.new do |spec| spec.add_dependency "build-uri", "~> 1.0" spec.add_dependency "build-text", "~> 1.0" - spec.add_dependency "samovar", "~> 1.6" + spec.add_dependency "samovar", "~> 1.7" # This could be a good option in the future for teapot fetch: #spec.add_dependency "rugged"