lib/vendorificator/environment.rb in vendorificator-0.5.git.v0.4.0.17.g26d50d8 vs lib/vendorificator/environment.rb in vendorificator-0.5.git.v0.4.0.60.g9c35209

- old
+ new

@@ -4,27 +4,32 @@ require 'vendorificator/config' module Vendorificator class Environment attr_reader :config - attr_accessor :shell, :vendor_instances + attr_accessor :vendor_instances, :io - def initialize(vendorfile=nil, &block) + def initialize(shell, verbosity = :default, vendorfile = nil, &block) @vendor_instances = [] + @io = IOProxy.new(shell, verbosity) + @vendorfile = find_vendorfile(vendorfile) + @vendor_block = block @config = Vendorificator::Config.new @config.environment = self - if vendorfile || !block_given? - @config.read_file(find_vendorfile(vendorfile).to_s) - end - @config.instance_eval(&block) if block_given? + end - self.each_vendor_instance{ |mod| mod.compute_dependencies! } + def shell + io.shell end + def say(*args) + io.say(*args) + end + def say_status(*args) - shell.say_status(*args) if shell + io.say_status(*args) end # Main MiniGit instance def git @git ||= MiniGit::new(config[:vendorfile_path]) @@ -47,14 +52,16 @@ # # options - The Hash of options. # # Returns nothing. def pull_all(options = {}) + load_vendorfile + ensure_clean! remotes = options[:remote] ? options[:remote].split(',') : config[:remotes] remotes.each do |remote| - indent 'remote', remote do + indent :default, 'remote', remote do pull(remote, options) end end end @@ -66,11 +73,14 @@ def pull(remote, options={}) raise RuntimeError, "Unknown remote #{remote}" unless remotes.include?(remote) git.fetch(remote) git.fetch({:tags => true}, remote) - git.fetch(remote, 'refs/notes/vendor:refs/notes/vendor') + begin + git.fetch(remote, 'refs/notes/vendor:refs/notes/vendor') + rescue MiniGit::GitError # ignore + end ref_rx = /^refs\/remotes\/#{Regexp.quote(remote)}\// remote_branches = Hash[ git.capturing.show_ref. lines. map(&:split). @@ -80,24 +90,24 @@ each_vendor_instance do |mod| ours = mod.head theirs = remote_branches[mod.branch_name] if theirs if not ours - say_status 'new', mod.branch_name, :yellow + say_status :default, 'new', mod.branch_name, :yellow git.branch({:track => true}, mod.branch_name, theirs) unless options[:dry_run] elsif ours == theirs - say_status 'unchanged', mod.branch_name + say_status :default, 'unchanged', mod.branch_name elsif fast_forwardable?(theirs, ours) - say_status 'updated', mod.name, :yellow + say_status :default, 'updated', mod.name, :yellow mod.in_branch { git.merge({:ff_only => true}, theirs) } unless options[:dry_run] elsif fast_forwardable?(ours, theirs) - say_status 'older', mod.branch_name + say_status :default, 'older', mod.branch_name else - say_status 'complicated', mod.branch_name, :red + say_status :default, 'complicated', mod.branch_name, :red end else - say_status 'unknown', mod.branch_name + say_status :default, 'unknown', mod.branch_name end end end # Public: Displays info about the last merged version of module. @@ -105,78 +115,105 @@ # mod - String with the module name # options - Hash containing options # # Returns nothing. def info(mod_name, options = {}) + load_vendorfile + if vendor = find_vendor_instance_by_name(mod_name) - shell.say "Module name: #{vendor.name}\n" - shell.say "Module category: #{vendor.category}\n" - shell.say "Module merged version: #{vendor.merged_version}\n" - shell.say "Module merged notes: #{vendor.merged_notes.ai}\n" + say :default, "Module name: #{vendor.name}\n" + say :default, "Module group: #{vendor.group}\n" + say :default, "Module merged version: #{vendor.merged_version}\n" + say :default, "Module merged notes: #{vendor.merged_notes.ai}\n" elsif (commit = Commit.new(mod_name, git)).exists? - shell.say "Branches that contain this commit: #{commit.branches.join(', ')}\n" - shell.say "Vendorificator notes on this commit: #{commit.notes.ai}\n" + say :default, "Branches that contain this commit: #{commit.branches.join(', ')}\n" + say :default, "Vendorificator notes on this commit: #{commit.notes.ai}\n" else - shell.say "Module or ref #{mod_name.inspect} not found." + say :default, "Module or ref #{mod_name.inspect} not found." end end + # Public: Displays info about current modules. + # + # Returns nothing. + def list + load_vendorfile + + each_vendor_instance do |mod| + shell.say "Module: #{mod.name}, version: #{mod.version}" + end + end + + # Public: Displays info about outdated modules. + # + # Returns nothing. + def outdated + load_vendorfile + + outdated = [] + each_vendor_instance do |mod| + outdated << mod if [:unpulled, :unmerged, :outdated].include? mod.status + end + + outdated.each { |mod| say_status :quiet, 'outdated', mod.name } + end + # Public: Push changes on module branches. # # options - The Hash containing options # # Returns nothing. def push(options = {}) + load_vendorfile + ensure_clean! pushable = [] - each_vendor_instance{ |mod| pushable += mod.pushable_refs } + each_vendor_instance { |mod| pushable += mod.pushable_refs } + pushable << 'refs/notes/vendor' if has_notes? + remotes = options[:remote] ? options[:remote].split(',') : config[:remotes] remotes.each do |remote| git.push remote, pushable - git.push remote, :tags => true - git.push remote, 'refs/notes/vendor' end end # Public: Runs all the vendor modules. # # options - The Hash of options. # # Returns nothing. def sync(options = {}) + load_vendorfile + ensure_clean! config[:use_upstream_version] = options[:update] metadata = metadata_snapshot each_vendor_instance(*options[:modules]) do |mod| - say_status :module, mod.name + say_status :default, :module, mod.name indent do mod.run!(:metadata => metadata) end end end # Public: Goes through all the Vendor instances and runs the block # - # modules - ? + # modules - An Array of vendor modules to yield the block for. # # Returns nothing. def each_vendor_instance(*modules) - modpaths = modules.map { |m| File.expand_path(m) } - # We don't use @vendor_instances.each here, because Vendor#run! is # explicitly allowed to append to instantiate new dependencies, and #each # fails to catch up on some Ruby implementations. i = 0 while true break if i >= @vendor_instances.length mod = @vendor_instances[i] - yield mod if modules.empty? || - modules.include?(mod.name) || - modpaths.include?(mod.work_dir) + yield mod if modules.empty? || mod.included_in_list?(modules) i += 1 end end # Public: Checks if the repository is clean. @@ -202,39 +239,65 @@ end # Public: returns `config[:root_dir]` relative to Git repository root def relative_root_dir @relative_root_dir ||= config[:root_dir].relative_path_from( - Pathname.new(git.git_work_tree)) + Pathname.new(git.git_work_tree) + ) end # Public: Returns module with given name def [](name) vendor_instances.find { |v| v.name == name } end + # Public: Loads the vendorfile. + # + # Returns nothing. + def load_vendorfile + raise RuntimeError, 'Vendorfile has been already loaded!' if @vendorfile_loaded + + if @vendorfile + @config.read_file @vendorfile.to_s + else + raise MissingVendorfileError unless @vendor_block + end + @config.instance_eval(&@vendor_block) if @vendor_block + + each_vendor_instance{ |mod| mod.compute_dependencies! } + + @vendorfile_loaded = true + end + + # Public: Checks if vendorfile has been already loaded. + # + # Returns boolean. + def vendorfile_loaded? + defined?(@vendorfile_loaded) && @vendorfile_loaded + end + private - # Private: Finds a vendor instance by module name. + # Private: Finds a vendor instance by module (qualified) name, path or branch. # - # mod_name - The String containing the module name. + # mod_name - The String containing the module id. # # Returns Vendor instance. def find_vendor_instance_by_name(mod_name) - each_vendor_instance do |mod| - return mod if mod.name == mod_name + each_vendor_instance(mod_name) do |mod| + return mod end nil end # Private: Finds the vendorfile to use. # # given - the optional String containing vendorfile path. # # Returns a String containing the vendorfile path. - def find_vendorfile(given=nil) - given = [ given, ENV['VENDORFILE'] ].find do |candidate| + def find_vendorfile(given = nil) + given = [given, ENV['VENDORFILE']].find do |candidate| candidate && !(candidate.respond_to?(:empty?) && candidate.empty?) end return given if given Pathname.pwd.ascend do |dir| @@ -245,15 +308,15 @@ return vf if vf.exist? # avoid stepping above the tmp directory when testing if ENV['VENDORIFICATOR_SPEC_RUN'] && dir.join('vendorificator.gemspec').exist? - raise ArgumentError, "Vendorfile not found" + break end end - raise ArgumentError, "Vendorfile not found" + return nil end # Private: Aborts on a dirty repository. # # Returns nothing. @@ -262,14 +325,25 @@ end # Private: Indents the output. # # Returns nothing. - def indent(*args, &block) - say_status *args unless args.empty? + def indent(verb_level = :default, *args, &block) + say_status verb_level, *args unless args.empty? shell.padding += 1 if shell yield ensure shell.padding -= 1 if shell end + + # Private: Checks if there are git vendor notes. + # + # Returns true/false. + def has_notes? + git.capturing.rev_parse({:quiet => true, :verify => true}, 'refs/notes/vendor') + true + rescue MiniGit::GitError + false + end + end end