diff --git a/lib/librarian/puppet/cli.rb b/lib/librarian/puppet/cli.rb index afb8e88c..1f3eddc2 100644 --- a/lib/librarian/puppet/cli.rb +++ b/lib/librarian/puppet/cli.rb @@ -47,6 +47,8 @@ def init option "destructive", :type => :boolean, :default => false option "local", :type => :boolean, :default => false option "use-v1-api", :type => :boolean, :default => true + option "use-forge", :type => :boolean + option "git-destructive", :type => :boolean def install ensure! @@ -63,6 +65,12 @@ def install end environment.config_db.local['use-v1-api'] = options['use-v1-api'] ? '1' : nil + unless options["use-forge"].nil? + environment.config_db.local['use-forge'] = options['use-forge'].to_s + end + unless options["git-destructive"].nil? + environment.config_db.local['git-destructive'] = options['git-destructive'].to_s + end environment.config_db.local['mode'] = options['local'] ? 'local' : nil resolve! @@ -84,6 +92,8 @@ def update(*names) option "strip-dot-git", :type => :boolean option "path", :type => :string option "destructive", :type => :boolean, :default => false + option "use-forge", :type => :boolean + option "git-destructive", :type => :boolean def package environment.vendor! install diff --git a/lib/librarian/puppet/environment.rb b/lib/librarian/puppet/environment.rb index d5024159..50e61579 100644 --- a/lib/librarian/puppet/environment.rb +++ b/lib/librarian/puppet/environment.rb @@ -57,6 +57,18 @@ def local? def use_v1_api config_db['use-v1-api'] end + + def use_forge + config_db['use-forge'].to_s == 'false' ? false : true + end + + def git_destructive + config_db['git-destructive'].to_s == 'false' ? false : true + end + + def verbose? + config_db['verbose'].to_s == 'false' ? false : true + end end end end diff --git a/lib/librarian/puppet/source/git.rb b/lib/librarian/puppet/source/git.rb index e2c09ea1..283d976d 100644 --- a/lib/librarian/puppet/source/git.rb +++ b/lib/librarian/puppet/source/git.rb @@ -6,6 +6,7 @@ module Source class Git class Repository def hash_from(remote, reference) + branch_names = remote_branch_names[remote] if branch_names.include?(reference) reference = "#{remote}/#{reference}" @@ -14,6 +15,57 @@ def hash_from(remote, reference) command = %W(rev-parse #{reference}^{commit} --quiet) run!(command, :chdir => true).strip end + + # Return true if the repository has local modifications, false otherwise. + def dirty? + # Ignore anything that's not a git repository + # This is relevant for testing scenarios + return false unless self.git? + + status = false + _path = relative_path_to(path).to_s + begin + Librarian::Posix.run!(%W{git update-index -q --ignore-submodules --refresh}, :chdir => _path) + rescue Librarian::Posix::CommandFailure => e + status = "Could not update git index for '#{path}'" + end + + unless status + begin + Librarian::Posix.run!(%W{git diff-files --quiet --ignore-submodules --}, :chdir => _path) + rescue Librarian::Posix::CommandFailure => e + status = "'#{_path}' has unstaged changes" + end + end + + unless status + begin + Librarian::Posix.run!(%W{git diff-index --cached --quiet HEAD --ignore-submodules --}, :chdir => _path) + rescue Librarian::Posix::CommandFailure => e + status = "'#{_path}' has uncommitted changes" + end + end + + unless status + begin + untracked_files = Librarian::Posix.run!(%W{git ls-files -o -d --exclude-standard}, :chdir => _path) + + unless untracked_files.empty? + untracked_files.strip! + + if untracked_files.lines.count > 0 + status = "'#{_path}' has untracked files" + end + end + + rescue Librarian::Posix::CommandFailure => e + # We should never get here + raise Error, "Failure running 'git ls-files -o -d --exclude-standard' at '#{_path}'" + end + end + + status + end end end end diff --git a/lib/librarian/puppet/source/local.rb b/lib/librarian/puppet/source/local.rb index 4a3744ce..f7100c68 100644 --- a/lib/librarian/puppet/source/local.rb +++ b/lib/librarian/puppet/source/local.rb @@ -9,23 +9,96 @@ module Local def install!(manifest) manifest.source == self or raise ArgumentError + if environment.verbose? + info { "Processing #{manifest.name}" } + end + debug { "Installing #{manifest}" } name, version = manifest.name, manifest.version found_path = found_path(name) - raise Error, "Path for #{name} doesn't contain a puppet module" if found_path.nil? - unless name.include? '/' or name.include? '-' - warn { "Invalid module name '#{name}', you should qualify it with 'ORGANIZATION-#{name}' for resolution to work correctly" } - end + # We only care about this if we're fetching from a Forge + if found_path || self.is_a?(Librarian::Puppet::Source::Forge) + raise Error, "Path for #{name} doesn't contain a puppet module" if found_path.nil? + + unless name.include? '/' or name.include? '-' + warn { "Invalid module name '#{name}', you should qualify it with 'ORGANIZATION-#{name}' for resolution to work correctly" } + end - install_path = environment.install_path.join(module_name(name)) - if install_path.exist? && rsync? != true - debug { "Deleting #{relative_path_to(install_path)}" } - install_path.rmtree + install_path = environment.install_path.join(module_name(name)) + elsif !repository_cached + raise Error, "Could not find cached version of #{name} for installation" + else + found_path = repository_cache_path + install_path = environment.project_path + path.to_s end - install_perform_step_copy!(found_path, install_path) + install_repo = Git::Repository.new(environment,install_path) + + if install_repo.git? + _install_path = relative_path_to(install_path) + + if environment.git_destructive + debug { "Performing git hard reset of '#{_install_path}'" } + + install_repo.reset_hard! + install_repo.clean! + end + + if install_repo.dirty? + warn { "#{install_repo.dirty?}, skipping..." } + else + # Try to do nicer git operations when possible + _remote_repo = 'librarian_origin' + + begin + Librarian::Posix.run!(%W{git remote add #{_remote_repo} #{repository_cache_path}}, :chdir => _install_path) + rescue Librarian::Posix::CommandFailure => e + unless e.to_s =~ /already exists/ + raise Error, "Could not update git repository at #{_install_path}" + end + end + + install_repo.fetch!(_remote_repo) + + if environment.verbose? + warn "Checking out #{ref} in #{_install_path}" + end + install_repo.checkout!(ref) + + begin + _target_ref = ref + + # Handle branches vs absolute refs + if repository.remote_branch_names[repository.default_remote].include?(_target_ref) + _target_ref = "#{repository.default_remote}/#{_target_ref}" + end + + ff_output = Librarian::Posix.run!(%W{git pull --ff-only #{_remote_repo} #{_target_ref}}, :chdir => _install_path) + + if ff_output =~ /Updating\s+.*\.\.(.*)\s*$/ + warn { "Updated '#{_install_path}' to #{$1}" } + end + rescue Librarian::Posix::CommandFailure => e + warn { "Fast forward of git repo at '#{_install_path}' failed...skipping" } + end + + begin + Librarian::Posix.run!(%W{git remote rm #{_remote_repo}}, :chdir => _install_path) + rescue Librarian::Posix::CommandFailure => e + # We don't really care if this fails. + debug { "Removal of the '#{_remote_repo}' git remote failed" } + end + end + else + if install_path.exist? && rsync? != true + debug { "Deleting #{relative_path_to(install_path)}" } + install_path.rmtree + end + + install_perform_step_copy!(found_path, install_path) + end end def fetch_version(name, extra) @@ -43,9 +116,13 @@ def fetch_dependencies(name, version, extra) end parsed_metadata['dependencies'].each do |d| - gem_requirement = Librarian::Dependency::Requirement.new(d['version_requirement']).to_gem_requirement - new_dependency = Dependency.new(d['name'], gem_requirement, forge_source) - dependencies << new_dependency + if environment.use_forge + gem_requirement = Librarian::Dependency::Requirement.new(d['version_requirement']).to_gem_requirement + new_dependency = Dependency.new(d['name'], gem_requirement, forge_source) + dependencies << new_dependency + end + + dependencies end dependencies diff --git a/lib/librarian/puppet/version.rb b/lib/librarian/puppet/version.rb index 377a7410..258c7a9d 100644 --- a/lib/librarian/puppet/version.rb +++ b/lib/librarian/puppet/version.rb @@ -1,5 +1,5 @@ module Librarian module Puppet - VERSION = "2.2.1" + VERSION = "2.2.3" end end