Skip to content

Commit

Permalink
Support nanoc environments
Browse files Browse the repository at this point in the history
Introduce basic support for nanoc environment:
- nanoc command is updated to include --env argument
- config are overriden using the active environment if any
- unless define in environment, output_dir is {{output_dir}}/{{env_name}}

Setting environments is done in nanoc.yaml using the `environments` property.
Example usage is:

```
output_dir: output

environments:
  default: &default
    base_url: ...
    ...
  development:
    <<: *default
    base_url: ...
  production:
    <<: *default
    base_url: ...
  yet_another_env:
    <<: *default
    base_url: ...
    output_dir: build
```

Selecting working environment can be done:
- using environment variable `NANOC_ENVIRONMENT`
- using `nanoc --env=[<value>]`
  • Loading branch information
barraq committed Jun 7, 2016
1 parent f4e0f02 commit 8433fe5
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 17 deletions.
25 changes: 22 additions & 3 deletions lib/nanoc/base/entities/configuration.rb
Expand Up @@ -31,10 +31,14 @@ class Configuration
string_pattern_type: 'glob',
}.freeze

attr_reader :env

# Creates a new configuration with the given hash.
#
# @param [Hash] hash The actual configuration hash
def initialize(hash = {})
# @param [Symbol, String] env The active environment for this configuration
def initialize(hash = {}, env = nil)
@env = env
@wrapped = hash.__nanoc_symbolize_keys_recursively
end

Expand All @@ -47,6 +51,21 @@ def with_defaults
self.class.new(new_wrapped)
end

def with_environment(env = nil)
return self unless @wrapped.key? :environments

# Set active environment
env ||= ENV.fetch 'NANOC_ENVIRONMENT', :default

# Load given environment configuration
env_config = @wrapped[:environments][env.to_sym] || {}

# Handle specific properties
env_config[:output_dir] ||= File.join(@wrapped[:output_dir].to_s, env.to_s)

self.class.new(@wrapped, env).merge(env_config)
end

def to_h
@wrapped
end
Expand Down Expand Up @@ -76,11 +95,11 @@ def []=(key, value)
end

def merge(hash)
self.class.new(@wrapped.merge(hash.to_h))
self.class.new(@wrapped.merge(hash.to_h), @env)
end

def without(key)
self.class.new(@wrapped.reject { |k, _v| k == key })
self.class.new(@wrapped.reject { |k, _v| k == key }, @env)
end

def update(hash)
Expand Down
2 changes: 1 addition & 1 deletion lib/nanoc/base/repos/checksum_store.rb
Expand Up @@ -6,7 +6,7 @@ module Nanoc::Int
class ChecksumStore < ::Nanoc::Int::Store
# @param [Nanoc::Int::Site] site
def initialize(site: nil)
super('tmp/checksums', 1)
super(File.join('tmp', (site.config.env if site).to_s, 'checksums'), 1)

@site = site

Expand Down
4 changes: 2 additions & 2 deletions lib/nanoc/base/repos/compiled_content_cache.rb
Expand Up @@ -4,8 +4,8 @@ module Nanoc::Int
#
# @api private
class CompiledContentCache < ::Nanoc::Int::Store
def initialize
super('tmp/compiled_content', 2)
def initialize(env: nil)
super(File.join('tmp', env.to_s, 'compiled_content'), 2)

@cache = {}
end
Expand Down
2 changes: 1 addition & 1 deletion lib/nanoc/base/repos/config_loader.rb
Expand Up @@ -40,7 +40,7 @@ def new_from_cwd
apply_parent_config(
Nanoc::Int::Configuration.new(YAML.load_file(filename)),
[filename],
).with_defaults
).with_defaults.with_environment
end

# @api private
Expand Down
4 changes: 2 additions & 2 deletions lib/nanoc/base/repos/dependency_store.rb
Expand Up @@ -5,8 +5,8 @@ class DependencyStore < ::Nanoc::Int::Store
attr_reader :objects

# @param [Array<Nanoc::Int::Item, Nanoc::Int::Layout>] objects
def initialize(objects)
super('tmp/dependencies', 4)
def initialize(objects, env: nil)
super(File.join('tmp', env.to_s, 'dependencies'), 4)

@objects = objects
@graph = Nanoc::Int::DirectedGraph.new([nil] + @objects)
Expand Down
4 changes: 2 additions & 2 deletions lib/nanoc/base/repos/rule_memory_store.rb
Expand Up @@ -4,8 +4,8 @@ module Nanoc::Int
#
# @api private
class RuleMemoryStore < ::Nanoc::Int::Store
def initialize
super('tmp/rule_memory', 1)
def initialize(env: nil)
super(File.join('tmp', env.to_s, 'rule_memory'), 1)

@rule_memories = {}
end
Expand Down
6 changes: 3 additions & 3 deletions lib/nanoc/base/services/compiler_loader.rb
Expand Up @@ -2,10 +2,10 @@ module Nanoc::Int
# @api private
class CompilerLoader
def load(site)
rule_memory_store = Nanoc::Int::RuleMemoryStore.new
rule_memory_store = Nanoc::Int::RuleMemoryStore.new env: site.config.env

dependency_store =
Nanoc::Int::DependencyStore.new(site.items.to_a + site.layouts.to_a)
Nanoc::Int::DependencyStore.new(site.items.to_a + site.layouts.to_a, env: site.config.env)

checksum_store =
Nanoc::Int::ChecksumStore.new(site: site)
Expand All @@ -25,7 +25,7 @@ def load(site)
)

params = {
compiled_content_cache: Nanoc::Int::CompiledContentCache.new,
compiled_content_cache: Nanoc::Int::CompiledContentCache.new(env: site.config.env),
checksum_store: checksum_store,
rule_memory_store: rule_memory_store,
dependency_store: dependency_store,
Expand Down
4 changes: 4 additions & 0 deletions lib/nanoc/cli/commands/nanoc.rb
Expand Up @@ -10,6 +10,10 @@
Nanoc::CLI.debug = true
end

opt :e, :env, 'set environment', argument: :optional do |value|
ENV.store 'NANOC_ENVIRONMENT', value || :default
end

opt :h, :help, 'show the help message and quit' do |_value, cmd|
puts cmd.help
exit 0
Expand Down
36 changes: 33 additions & 3 deletions spec/nanoc/base/entities/configuration_spec.rb
@@ -1,10 +1,9 @@
describe Nanoc::Int::Configuration do
let(:configuration) { described_class.new(hash) }

let(:hash) { { foo: 'bar' } }
let(:config) { described_class.new(hash) }

describe '#key?' do
subject { configuration.key?(key) }
subject { config.key?(key) }

context 'non-existent key' do
let(:key) { :donkey }
Expand All @@ -16,4 +15,35 @@
it { is_expected.to be }
end
end

context 'with environments defined' do
let(:hash) { { foo: 'bar', environments: { test: { foo: 'test-bar' }, default: { foo: 'default-bar' } } } }
let(:config) { described_class.new(hash).with_environment(env) }

subject { config }

context 'with existing environment' do
let(:env) { :test }

it 'inherits options from given environment' do
expect(subject[:foo]).to eq('test-bar')
end
end

context 'with unknown environment' do
let(:env) { :wtf }

it 'does not inherits options from any environment' do
expect(subject[:foo]).to eq('bar')
end
end

context 'without given environment' do
let(:env) { nil }

it 'inherits options from default environment' do
expect(subject[:foo]).to eq('default-bar')
end
end
end
end
19 changes: 19 additions & 0 deletions spec/nanoc/base/repos/config_loader_spec.rb
Expand Up @@ -52,6 +52,25 @@
expect(subject[:parent_config_file]).to be_nil
end
end

context 'config file present and environment defined' do
before do
File.write('nanoc.yaml', YAML.dump({ foo: 'bar', environments: { test: { foo: 'test-bar' }, default: { foo: 'default-bar' } } }))
end

it 'returns the configuration' do
expect(subject).to be_a(Nanoc::Int::Configuration)
end

it 'has the test environment custom option' do
allow(ENV).to receive(:fetch).with('NANOC_ENVIRONMENT', :default).and_return('test')
expect(subject[:foo]).to eq('test-bar')
end

it 'has the default environment custom option' do
expect(subject[:foo]).to eq('default-bar')
end
end
end

describe '.cwd_is_nanoc_site? + .config_filename_for_cwd' do
Expand Down

0 comments on commit 8433fe5

Please sign in to comment.