Skip to content

Commit

Permalink
Merge branch 'release-4.2.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
denisdefreyne committed Jul 10, 2016
2 parents 4fc7c2d + 735f50e commit 6831551
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 12 deletions.
1 change: 1 addition & 0 deletions lib/nanoc.rb
Expand Up @@ -22,6 +22,7 @@ def self.on_windows?

# Load external dependencies
require 'hamster'
require 'ref'

# Load general requirements
require 'digest'
Expand Down
1 change: 1 addition & 0 deletions lib/nanoc/base.rb
Expand Up @@ -25,6 +25,7 @@ module Nanoc::Int
require_relative 'base/contracts_support'

require_relative 'base/entities'
require_relative 'base/feature'
require_relative 'base/repos'
require_relative 'base/services'
require_relative 'base/views'
11 changes: 11 additions & 0 deletions lib/nanoc/base/feature.rb
@@ -0,0 +1,11 @@
module Nanoc
# @api private
module Feature
TRUES = %w(y yes 1 t true).freeze

def self.enabled?(name)
env_name = "NANOC_FEATURE_#{name.upcase}"
TRUES.include?(ENV.fetch(env_name, 'f').downcase)
end
end
end
19 changes: 9 additions & 10 deletions lib/nanoc/base/memoization.rb
Expand Up @@ -15,9 +15,12 @@ def initialize(ref)
end

def inspect
@ref.inspect
rescue WeakRef::RefError
'<weak ref collected>'
obj = @ref.object
if obj
obj.inspect
else
'<garbage collected>'
end
end
end

Expand Down Expand Up @@ -75,17 +78,13 @@ def memoize(method_name)

value = NONE
if method_cache.key?(args)
value =
begin
method_cache[args].ref.value
rescue WeakRef::RefError
NONE
end
object = method_cache[args].ref.object
value = object ? object.value : NONE
end

if value.equal?(NONE)
send(original_method_name, *args).tap do |r|
method_cache[args] = Wrapper.new(WeakRef.new(Value.new(r)))
method_cache[args] = Wrapper.new(Ref::SoftReference.new(Value.new(r)))
end
else
value
Expand Down
40 changes: 38 additions & 2 deletions lib/nanoc/cli/commands/compile.rb
Expand Up @@ -14,6 +14,7 @@
SKIP - The item was deemed not outdated and was therefore not recompiled
EOS
flag nil, :profile, 'profile compilation' if Nanoc::Feature.enabled?('PROFILER')

module Nanoc::CLI::Commands
class Compile < ::Nanoc::CLI::CommandRunner
Expand Down Expand Up @@ -49,6 +50,18 @@ def start
# @return [void]
def stop
end

# @api private
def start_safely
start
@_started = true
end

# @api private
def stop_safely
stop if @_started
@_started = false
end
end

# Generates diffs for every output file written
Expand Down Expand Up @@ -354,6 +367,28 @@ def log(level, action, path, duration)
end
end

# Records a profile using StackProf
class StackProfProfiler < Listener
PROFILE_FILE = 'tmp/stackprof_profile'.freeze

# @see Listener#enable_for?
def self.enable_for?(command_runner)
command_runner.options.fetch(:profile, false)
end

# @see Listener#start
def start
require 'stackprof'
StackProf.start(mode: :cpu)
end

# @see Listener#stop
def stop
StackProf.stop
StackProf.results(PROFILE_FILE)
end
end

attr_accessor :listener_classes

def initialize(options, arguments, command)
Expand Down Expand Up @@ -392,6 +427,7 @@ def default_listener_classes
Nanoc::CLI::Commands::Compile::TimingRecorder,
Nanoc::CLI::Commands::Compile::GCController,
Nanoc::CLI::Commands::Compile::FileActionPrinter,
Nanoc::CLI::Commands::Compile::StackProfProfiler,
]
end

Expand All @@ -401,7 +437,7 @@ def setup_listeners
.select { |klass| klass.enable_for?(self) }
.map { |klass| klass.new(reps: reps) }

@listeners.each(&:start)
@listeners.each(&:start_safely)
end

def listeners
Expand All @@ -416,7 +452,7 @@ def run_listeners_while
end

def teardown_listeners
@listeners.each(&:stop)
@listeners.each(&:stop_safely)
end

def reps
Expand Down
1 change: 1 addition & 0 deletions nanoc.gemspec
Expand Up @@ -26,6 +26,7 @@ Gem::Specification.new do |s|

s.add_runtime_dependency('cri', '~> 2.3')
s.add_runtime_dependency('hamster', '~> 3.0')
s.add_runtime_dependency('ref', '~> 2.0')

s.add_development_dependency('bundler', '>= 1.7.10', '< 2.0')
end
29 changes: 29 additions & 0 deletions spec/nanoc/base/feature_spec.rb
@@ -0,0 +1,29 @@
describe Nanoc::Feature do
describe '.enabled?' do
subject { described_class.enabled?(feature_name) }

let(:feature_name) { 'magic' }

context 'disabled' do
context 'not set' do
it { is_expected.not_to be }
end

%w(0 n N no No NO false False fAlSe FALSE donkey).each do |val|
context "set to #{val}" do
before { ENV['NANOC_FEATURE_MAGIC'] = val }
it { is_expected.not_to be }
end
end
end

context 'enabled' do
%w(1 y Y yes yEs YES t True tRuE TRUE).each do |val|
context "set to #{val}" do
before { ENV['NANOC_FEATURE_MAGIC'] = val }
it { is_expected.to be }
end
end
end
end
end
64 changes: 64 additions & 0 deletions spec/nanoc/cli/commands/compile_spec.rb
@@ -0,0 +1,64 @@
describe Nanoc::CLI::Commands::Compile::Listener do
let(:klass) do
Class.new(described_class) do
attr_reader :started
attr_reader :stopped

def initialize
@started = false
@stopped = false
end

def start
@started = true
end

def stop
@stopped = true
end
end
end

subject { klass.new }

it 'starts' do
subject.start
expect(subject.started).to be
end

it 'stops' do
subject.start
subject.stop
expect(subject.stopped).to be
end

it 'starts safely' do
subject.start_safely
expect(subject.started).to be
end

it 'stops safely' do
subject.start_safely
subject.stop_safely
expect(subject.stopped).to be
end

context 'listener that does not start or stop properly' do
let(:klass) do
Class.new(described_class) do
def start
raise 'boom'
end

def stop
raise 'boom'
end
end
end

it 'raises on start, but not stop' do
expect { subject.start_safely }.to raise_error(RuntimeError)
expect { subject.stop_safely }.not_to raise_error
end
end
end

0 comments on commit 6831551

Please sign in to comment.