Skip to content

Instantly share code, notes, and snippets.

@vdinovi
Last active December 1, 2020 22:37
Show Gist options
  • Select an option

  • Save vdinovi/8d366a58e8cd232b4046727e3fe3be47 to your computer and use it in GitHub Desktop.

Select an option

Save vdinovi/8d366a58e8cd232b4046727e3fe3be47 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
# frozen_string_literal: true
require "colorize"
require "open3"
require "optparse"
require "concurrent"
MAX_ACTIVE_THREADS = 5
THREAD_TIMEOUT = 5
USAGE = "k8-git-copy -l LOCAL_PATH -r REMOTE_PATH -n NAMESPACE -p POD -c CONTAINER -b BASE_BRANCH"
OPTION_DEFAULTS = {
:base_branch => { default: "HEAD"},
:local_path => { default: "*"},
:remote_path => { env: "K8_REMOTE_PATH" },
:namespace => { env: "K8_NAMESPACE" },
:pod => { env: "K8_POD" },
:container => { env: "K8_CONTAINER" },
}.freeze
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: #{USAGE}".yellow
opts.on("-bBASE_BRANCH", "--base-branch=BASE_BRANCH", "Base branch to diff from") { |base_branch| options[:base_branch] = base_branch }
opts.on("-lLOCAL_PATH", "--local-path=LOCAL_PATH", "Local file path") { |local_path| options[:local_path] = local_path }
opts.on("-rREMOTE_PATH", "--remote-pateh=REMOTE_PATH", "Remote file path") { |remote_path| options[:remote_path] = remote_path }
opts.on("-nNAMESPACE", "--namespace=NAMESPACE", "K8 namespace") { |namespace| options[:namespace] = namespace }
opts.on("-pPOD", "--pod=POD", "K8 pod") { |pod| options[:pod] = pod }
opts.on("-cCONTAINER", "--container=CONTAINER", "K8 container") { |container| options[:container] = container }
end.parse!
OPTION_DEFAULTS.each do |option_name, defaults|
options[option_name] ||= ENV[defaults[:env]] if defaults[:env]
options[option_name] ||= defaults[:default] if defaults[:default]
if !options[option_name] || options[option_name].empty?
puts "missing option '#{option_name}'".colorize(:red)
puts USAGE.colorize(:yellow)
exit 1
end
end
err, root = Open3.popen3("/usr/local/bin/git rev-parse --show-toplevel") { |_stdin, stdout, stderr, _wait_thr| [stderr.read, stdout.read.strip] }
if !err.empty?
puts "Error: #{err.yellow}"
exit 1
end
puts (cmd = "/usr/local/bin/git diff --name-only #{options[:base_branch]} -- #{options[:local_path]}")
err, changed = Open3.popen3(cmd) { |_stdin, stdout, stderr, _wait_thr| [stderr.read, stdout.read.split("\n")] }
if !err.empty?
puts "Error: #{err.yellow}"
exit 1
end
if changed.empty?
puts "no files matching '#{options[:local_path]}' changed".colorize(:yellow)
end
sem = Concurrent::Semaphore.new(MAX_ACTIVE_THREADS)
changed.map do |path|
Thread.new do
sem.acquire
begin
Timeout.timeout(THREAD_TIMEOUT) do
local_path = "#{root}/#{path}"
remote_path = "#{options[:remote_path]}/#{path}"
cmd = "kubectl cp #{local_path} -n #{options[:namespace]} -c #{options[:container]} #{options[:pod]}:#{remote_path}"
err = Open3.popen3(cmd) { |_stdin, stdout, stderr, _wait_thr| stderr.read }
if !err.empty?
puts cmd.colorize(:red)
puts "Error: #{err.yellow}"
end
puts cmd.colorize(:green)
end
rescue Timeout::Error
puts "timeout while copying file #{path}".colorize(:red)
ensure
sem.release
end
end
end.each(&:join)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment