Skip to content
This repository has been archived by the owner on Apr 6, 2021. It is now read-only.

Commit

Permalink
Change tracking, env class, removed VCS code. Bump to v0.2.
Browse files Browse the repository at this point in the history
  • Loading branch information
nathankleyn committed Jan 23, 2015
1 parent 7f49d08 commit 37439f7
Show file tree
Hide file tree
Showing 17 changed files with 169 additions and 134 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.DS_Store
*.gem
coverage
.shanty
7 changes: 7 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Changelog

## v0.2.0 (22nd January, 2015)

* **Change tracking:** Added working changed flags to projects to allow CLI tasks to run just on projects that are different since last time. Note that this is a work in progress, as there are lots of things to still work on here (for example, it's currently implemented as a mutator, and it saves the change index even if the CLI command doesn't end up using it or fails to run).
* **Env class:** Added Env class to allow passing around of config, paths and other stuff separate to the TaskEnv (which contains the graph). An env instance is available to all mutators and discovers. TaskEnv is just a decorator of Env, so you can continue to call the methods you used to on it where you only have TaskEnv available (eg. in a task)!
* **Removed VCS/Git Code:** Now that we have change support that doesn't need a VCS, all of the VCS and Git stuff has been removed. This was all internal for now anyway, so shouldn't effect anybody. However, this does mean you can now use Shanty in any directory, rather than it having to be a VCS repository of some sort.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
shanty (0.1.0)
shanty (0.2.0)
algorithms (~> 0.6)
commander (~> 4.2)
deep_merge (~> 1.0)
Expand Down
5 changes: 3 additions & 2 deletions lib/shanty.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
require 'shanty/cli'
require 'shanty/discoverers/shantyfile'
require 'shanty/discoverers/rubygem'
require 'shanty/env'
require 'shanty/graph'
require 'shanty/mutators/bundler'
require 'shanty/mutators/git'
require 'shanty/mutators/changed'
require 'shanty/plugins/rspec'
require 'shanty/plugins/rubocop'
require 'shanty/task_env'
Expand All @@ -23,7 +24,7 @@ class Shanty
def start!
setup_i18n

Cli.new(TaskEnv.new).run
Cli.new(TaskEnv.new(Env.new)).run
end

private
Expand Down
8 changes: 7 additions & 1 deletion lib/shanty/discoverer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ class << self
attr_reader :discoverers
end

attr_reader :env

def initialize(env)
@env = env
end

def self.inherited(discoverer)
Util.logger.debug("Detected project discoverer #{discoverer}")
@discoverers ||= []
Expand All @@ -18,7 +24,7 @@ def self.inherited(discoverer)

def discover_all
self.class.discoverers.flat_map do |discoverer|
discoverer.new.discover
discoverer.new(env).discover
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/shanty/discoverers/rubygem.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module Shanty
# a directory
class RubygemDiscoverer < Discoverer
def discover
Dir['**/*.gemspec'].map do |path|
Dir[File.join(env.root, '**', '*.gemspec')].map do |path|
create_project_template(File.absolute_path(File.dirname(path))) do |project_template|
project_template.type = RubygemProject
end
Expand Down
2 changes: 1 addition & 1 deletion lib/shanty/discoverers/shantyfile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module Shanty
# customisation.
class ShantyfileDiscoverer < Discoverer
def discover
Dir['**/Shantyfile'].map do |path|
Dir[File.join(env.root, '**', 'Shantyfile')].map do |path|
create_project_template(File.absolute_path(File.dirname(path))) do |project_template|
project_template.priority = -1
end
Expand Down
51 changes: 51 additions & 0 deletions lib/shanty/env.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
require 'deep_merge'
require 'yaml'

module Shanty
#
class Env
CONFIG_FILE = '.shanty.yml'
DEFAULT_CONFIG = {}

def initialize
Dir.chdir(root) do
(config['require'] || {}).each do |requirement|
requirement = "#{requirement}/**/*.rb" unless requirement.include?('.rb')
Dir[requirement].each { |f| require(File.join(root, f)) }
end
end
end

def environment
@environment = ENV['SHANTY_ENV'] || 'local'
end

def root
@root ||= find_root
end

private

def config
return @config unless @config.nil?

file_config = YAML.load_file("#{root}/#{CONFIG_FILE}") || {}
@config = DEFAULT_CONFIG.deep_merge!(file_config[environment])
end

def find_root
if root_dir.nil?
fail "Could not find a #{CONFIG_FILE} file in this or any parent directories. \
Please run `shanty init` in the directory you want to be the root of your project structure."
end

root_dir
end

def root_dir
Pathname.new(Dir.pwd).ascend do |d|
return d if d.join(CONFIG_FILE).exist?
end
end
end
end
11 changes: 9 additions & 2 deletions lib/shanty/mutator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,22 @@ class << self
attr_reader :mutators
end

attr_reader :env, :graph

def initialize(env, graph)
@env = env
@graph = graph
end

def self.inherited(mutator)
Util.logger.debug("Detected mutator #{mutator}")
@mutators ||= []
@mutators << mutator
end

def apply_mutations(graph)
def apply_mutations
self.class.mutators.each do |mutator|
mutator.new.mutate(graph)
mutator.new(@env, @graph).mutate
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/shanty/mutators/bundler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
module Shanty
# Bundler mutator
class BundlerMutator < Mutator
def mutate(graph)
def mutate
graph.each do |project|
BundlerPlugin.add_to_project(project) if File.exist?(File.join(project.path, 'Gemfile'))
end
Expand Down
78 changes: 78 additions & 0 deletions lib/shanty/mutators/changed.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
require 'find'
require 'fileutils'
require 'set'
require 'shanty/mutator'

module Shanty
# Mutates the graph to mark projects which have changed since the last time they were built.
class ChangedMutator < Mutator
UNIT_SEPARATOR = "\u001F"

def mutate
FileUtils.mkdir(shanty_dir) unless File.directory?(shanty_dir)

self.cached_index = all_index_files.each_with_object({}) do |path, acc|
# Check if the file has changed between
next if unchanged_in_index?(path)
# Otherwise, it was modified, deleted or added, so update the index if the file still exists.
acc[path] = current_index[path] if current_index.include?(path)
mark_project_as_changed(path)
end
end

private

def shanty_dir
File.join(env.root, '.shanty')
end

def index_file
File.join(shanty_dir, 'index')
end

def all_index_files
Set.new(cached_index.keys + current_index.keys).to_a
end

def cached_index
return @cached_index unless @cached_index.nil?
return (@cached_index = {}) unless File.exist?(index_file)

@cached_index = File.open(index_file).each_line.each_with_object({}) do |line, acc|
path, *attrs = line.split(UNIT_SEPARATOR)
acc[path] = attrs
end
end

def cached_index=(new_index)
File.open(index_file, 'w+') do |f|
new_index.each do |path, attrs|
f.puts(attrs.unshift(path).join(UNIT_SEPARATOR))
end
end
end

def unchanged_in_index?(path)
cached = cached_index[path]
current = current_index[path]
!cached.nil? && !current.nil? && current == cached
end

def current_index
@current_index ||= Find.find(env.root).each_with_object({}) do |path, acc|
# FIXME: Pass in list of excludes and match as follows:
# next Find.prune if path =~ /(build|.git|.gradle)/
next unless File.exist?(path)
s = File.stat(path)
next if s.directory?

acc[path] = [s.mtime.to_i, s.size]
end
end

def mark_project_as_changed(path)
project = graph.owner_of_file(File.join(env.root, path))
project.changed = true unless project.nil?
end
end
end
22 changes: 0 additions & 22 deletions lib/shanty/mutators/git.rb

This file was deleted.

51 changes: 5 additions & 46 deletions lib/shanty/task_env.rb
Original file line number Diff line number Diff line change
@@ -1,64 +1,23 @@
require 'deep_merge'
require 'yaml'
require 'delegate'

module Shanty
#
class TaskEnv
CONFIG_FILE = '.shanty.yml'
DEFAULT_CONFIG = {}

def initialize
Dir.chdir(root) do
(config['require'] || {}).each do |requirement|
requirement = "#{requirement}/**/*.rb" unless requirement.include?('.rb')
Dir[requirement].each { |f| require(File.join(root, f)) }
end
end
end
class TaskEnv < SimpleDelegator
alias_method :env, :__getobj__

def graph
@graph ||= construct_project_graph
end

def environment
@environment = ENV['SHANTY_ENV'] || 'local'
end

def root
@root ||= find_root
end

private

def config
return @config unless @config.nil?

file_config = YAML.load_file("#{root}/#{CONFIG_FILE}") || {}
@config = DEFAULT_CONFIG.deep_merge!(file_config[environment])
end

def find_root
if root_dir.nil?
fail "Could not find a #{CONFIG_FILE} file in this or any parent directories. \
Please run `shanty init` in the directory you want to be the root of your project structure."
end

root_dir
end

def root_dir
Pathname.new(Dir.pwd).ascend do |d|
return d if d.join(CONFIG_FILE).exist?
end
end

def construct_project_graph
project_templates = Dir.chdir(root) do
Discoverer.new.discover_all.sort_by(&:priority).reverse.uniq(&:path)
Discoverer.new(env).discover_all.sort_by(&:priority).reverse.uniq(&:path)
end

Graph.new(project_templates).tap do |graph|
Mutator.new.apply_mutations(graph)
Mutator.new(env, graph).apply_mutations
end
end
end
Expand Down
31 changes: 0 additions & 31 deletions lib/shanty/vcs_range.rb

This file was deleted.

20 changes: 0 additions & 20 deletions lib/shanty/vcs_ranges/local_git.rb

This file was deleted.

Loading

0 comments on commit 37439f7

Please sign in to comment.