Download a Git repo without .git folderBackup utility for local git repositoriesCounting the number of days...
When does coming up with an idea constitute sufficient contribution for authorship?
"On one hand" vs "on the one hand."
Why are the books in the Game of Thrones citadel library shelved spine inwards?
Called into a meeting and told we are being made redundant (laid off) and "not to share outside". Can I tell my partner?
Eww, those bytes are gross
Why zero tolerance on nudity in space?
Quenching swords in dragon blood; why?
The vanishing of sum of coefficients: symmetric polynomials
How to deal with an incendiary email that was recalled
Early credit roll before the end of the film
Can a hotel cancel a confirmed reservation?
Why avoid shared user accounts?
Issues with new Macs: Hardware makes them difficult for me to use. What options might be available in the future?
Pendulum Rotation
Avoiding morning and evening handshakes
Why would the Pakistan airspace closure cancel flights not headed to Pakistan itself?
What to do when being responsible for data protection in your lab, yet advice is ignored?
Are there any outlying considerations if I treat donning a shield as an object interaction during the first round of combat?
What's a good word to describe a public place that looks like it wouldn't be rough?
Strange Sign on Lab Door
How can I improve my fireworks photography?
what does conditioning on a random variable mean?
Do authors have to be politically correct in article-writing?
What is the wife of a henpecked husband called?
Download a Git repo without .git folder
Backup utility for local git repositoriesCounting the number of days worked for all commiters to a git repoRuby script to create git reposUse git to get SHA-1 of repoDetermining if a file or URL is a git repo or archiveGit tag release build files and reset to commit withoutAutomating the download of a GitHub repoGenerates a bare git repo from existing one and copy it to a central serverBash script to symlink configuration files from git repo into home directoryEnsure that a directory reflects a specified Git commit
$begingroup$
Coming from Python, JavaScript and PHP, I'd like to learn to write Ruby in the way it's "supposed to". Well-written Python code is called "Pythonic", so I'd like to know how idiomatic my Ruby code is.
I've had great help from Rubocop, slapping my face if I didn't write properly, but I still feel some things can be done better.
Application
This set of scripts downloads a github/gitlab/bitbucket repository, removes the .git folder and moves it to the specified folder, so that the files are "de-git".
Some commands:
# Run tests (for regexes)
./degit.rb --test
# Extract repo to folder with repo name
./degit.rb zpqrtbnk/test-repo
# Extract tag/branch of repo to folder with repo name
./degit.rb zpqrtbnk/test-repo#temp
# Extract repo to specified folder
./degit.rb zpqrtbnk/test-repo some-folder
Code
Ruby v2.4.5
Idea came from degit by Rich Harris
degit.rb
#!/usr/bin/env ruby
require "tmpdir"
require_relative "repo"
require_relative "repo_type"
REPO_TYPES = {
github: RepoType.new("github", "https://github.com", "github.com"),
gitlab: RepoType.new("gitlab", "https://gitlab.com", "gitlab.com"),
bitbucket: RepoType.new("bitbucket", "https://bitbucket.org", "bitbucket.org"),
custom: RepoType.new("custom", :custom, :custom),
}.freeze
# TODO: Error handling
def main
repo_name = ARGV[0]
folder_name = ARGV[1]
raise "Required parameter repo name not specified" if repo_name.nil?
if repo_name == "--test"
require_relative "tests"
run_tests
return
end
degit repo_name, folder_name
end
def temp_dir
dir = Dir.mktmpdir("degit-", "/tmp")
at_exit { FileUtils.remove_entry(dir) }
dir
end
def degit(repo_name, folder_name)
repo = Repo.new repo_name
folder_name ||= repo.name
dest_dir = File.join Dir.pwd, folder_name
dir_exists = Dir.exist? dest_dir
if dir_exists
abort "Aborted" unless confirm_overwrite dest_dir
end
dir = temp_dir
tmp_repo_path = File.join(dir, folder_name)
cmd = repo.download_command tmp_repo_path
puts `#{cmd}`
FileUtils.remove_entry File.join(tmp_repo_path, ".git")
FileUtils.remove_entry dest_dir if dir_exists
FileUtils.mv(tmp_repo_path, Dir.pwd, force: true)
end
def confirm_overwrite(dest_dir)
print "Destination folder #{dest_dir} already exists. Overwrite folder? [y/n] "
# ARGV interferes with gets, so use STDIN.gets
input = STDIN.gets.chomp.downcase
return (input == "y") if %w[y n].include? input
# Continue to ask until input is either y or n
confirm_overwrite dest_dir
end
main if $PROGRAM_NAME == __FILE__
repo_type.rb
class RepoType
attr_reader :name, :full_url
def initialize(name, full_url, base_url, short_code=nil)
@name = name
@full_url = full_url
@base_url = base_url
@short_code = short_code || name.to_s.downcase
end
def id?(id)
[@short_code, @base_url].include? id
end
end
repo.rb
class Repo
attr_reader :type, :tag, :name
PREFIX_REGEX = %r{
A
((?<type>github|gitlab|bitbucket):)?
(?<owner>[w-]+)/(?<name>[w-]+)
(#(?<tag>[w-.]+))?
z
}xi.freeze
SSH_REGEX = %r{
A
(?<source_url>
git@(?<type>github.com|gitlab.com|bitbucket.org):
(?<owner>[w-]+)/(?<name>[w-]+)
(.git)?
)
(#(?<tag>[w-.]+))?
z
}xi.freeze
HTTPS_REGEX = %r{
A
(?<source_url>
https://(?<type>github.com|gitlab.com|bitbucket.org)/
(?<owner>[w-]+)/(?<name>[w-]+)
)
(#(?<tag>[w-.]+))?
z
}xi.freeze
def initialize(uri)
@uri = uri
raise "Required constant REPO_TYPES not defined" unless defined? REPO_TYPES
parse_uri
# debug unless @source_url.nil?
end
def valid_uri?
@uri.end_with?(".git") || @uri.include?("/")
end
def parse_uri
if @uri.end_with? ".git"
@type = REPO_TYPES[:custom]
return
end
repo = match_repo_info
return nil if repo.nil?
@owner = repo[:owner]
@name = repo[:name]
@tag = repo[:tag]
@source_url = make_source_url repo
end
def match_repo_info
[PREFIX_REGEX, SSH_REGEX, HTTPS_REGEX].each do |regex|
repo_matches = regex.match @uri
unless repo_matches.nil?
@type = find_repo_type repo_matches[:type]
return repo_matches
end
end
nil
end
def find_repo_type(type)
REPO_TYPES.each do |_, repo_type|
return repo_type if repo_type.id? type
end
REPO_TYPES[:github]
end
def make_source_url(repo)
return repo[:source_url] if repo.names.include? "source_url"
source_url = @type.full_url || @uri
"#{source_url}/#{@owner}/#{@name}"
end
def download_command(output_folder=nil)
tag_spec = @tag.nil? ? "" : "--branch #{@tag}"
parts = [
"git clone --quiet --depth 1",
tag_spec,
@source_url,
output_folder || @name,
]
parts.join " "
end
def debug
puts ""
puts "source_url: #{@source_url}" unless @source_url.nil?
puts "owner: #{@owner}" unless @owner.nil?
puts "name: #{@name}" unless @name.nil?
puts "tag: #{@tag}" unless @tag.nil?
puts "download cmd: #{download_command}"
end
end
tests.rb
VALID = %w[
user1/repo1
github:user2/repo2
git@github.com:user3/repo3
https://github.com/rmccue/test-repository
gitlab:user5/repo5
git@gitlab.com:user6/repo6
https://gitlab.com/user7/repo7
bitbucket:user8/repo8
git@bitbucket.org:user9/repo9
https://bitbucket.org/user0/repo0
].freeze
INVALID = %w[
http://github.com/user1/repo1
https://github.com/user2
https://github.comuser3/repo3
].freeze
WITH_TAG = %w[
user1/repo1#dev
user2/repo2#v1.2.3
user3/repo3#1234abcd
].freeze
WITH_GIT_SUFFIX = %w[
https://github.com/Rich-Harris/degit.git
user@host:~/repos/website.nl.git
].freeze
def pf(str)
print str
$stdout.flush
end
def run_tests
pf " VALID: "
VALID.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't valid" if repo.type.nil?
end
puts ""
pf " INVALID: "
INVALID.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't invalid" unless repo.type.nil?
end
puts ""
pf " WITH_TAG: "
WITH_TAG.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't valid" if repo.type.nil?
raise "#{r} has no tag" if repo.tag.nil?
end
puts ""
pf "WITH_GIT_SUFFIX: "
WITH_GIT_SUFFIX.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't valid" if repo.type.nil?
end
puts ""
end
beginner ruby console git
$endgroup$
add a comment |
$begingroup$
Coming from Python, JavaScript and PHP, I'd like to learn to write Ruby in the way it's "supposed to". Well-written Python code is called "Pythonic", so I'd like to know how idiomatic my Ruby code is.
I've had great help from Rubocop, slapping my face if I didn't write properly, but I still feel some things can be done better.
Application
This set of scripts downloads a github/gitlab/bitbucket repository, removes the .git folder and moves it to the specified folder, so that the files are "de-git".
Some commands:
# Run tests (for regexes)
./degit.rb --test
# Extract repo to folder with repo name
./degit.rb zpqrtbnk/test-repo
# Extract tag/branch of repo to folder with repo name
./degit.rb zpqrtbnk/test-repo#temp
# Extract repo to specified folder
./degit.rb zpqrtbnk/test-repo some-folder
Code
Ruby v2.4.5
Idea came from degit by Rich Harris
degit.rb
#!/usr/bin/env ruby
require "tmpdir"
require_relative "repo"
require_relative "repo_type"
REPO_TYPES = {
github: RepoType.new("github", "https://github.com", "github.com"),
gitlab: RepoType.new("gitlab", "https://gitlab.com", "gitlab.com"),
bitbucket: RepoType.new("bitbucket", "https://bitbucket.org", "bitbucket.org"),
custom: RepoType.new("custom", :custom, :custom),
}.freeze
# TODO: Error handling
def main
repo_name = ARGV[0]
folder_name = ARGV[1]
raise "Required parameter repo name not specified" if repo_name.nil?
if repo_name == "--test"
require_relative "tests"
run_tests
return
end
degit repo_name, folder_name
end
def temp_dir
dir = Dir.mktmpdir("degit-", "/tmp")
at_exit { FileUtils.remove_entry(dir) }
dir
end
def degit(repo_name, folder_name)
repo = Repo.new repo_name
folder_name ||= repo.name
dest_dir = File.join Dir.pwd, folder_name
dir_exists = Dir.exist? dest_dir
if dir_exists
abort "Aborted" unless confirm_overwrite dest_dir
end
dir = temp_dir
tmp_repo_path = File.join(dir, folder_name)
cmd = repo.download_command tmp_repo_path
puts `#{cmd}`
FileUtils.remove_entry File.join(tmp_repo_path, ".git")
FileUtils.remove_entry dest_dir if dir_exists
FileUtils.mv(tmp_repo_path, Dir.pwd, force: true)
end
def confirm_overwrite(dest_dir)
print "Destination folder #{dest_dir} already exists. Overwrite folder? [y/n] "
# ARGV interferes with gets, so use STDIN.gets
input = STDIN.gets.chomp.downcase
return (input == "y") if %w[y n].include? input
# Continue to ask until input is either y or n
confirm_overwrite dest_dir
end
main if $PROGRAM_NAME == __FILE__
repo_type.rb
class RepoType
attr_reader :name, :full_url
def initialize(name, full_url, base_url, short_code=nil)
@name = name
@full_url = full_url
@base_url = base_url
@short_code = short_code || name.to_s.downcase
end
def id?(id)
[@short_code, @base_url].include? id
end
end
repo.rb
class Repo
attr_reader :type, :tag, :name
PREFIX_REGEX = %r{
A
((?<type>github|gitlab|bitbucket):)?
(?<owner>[w-]+)/(?<name>[w-]+)
(#(?<tag>[w-.]+))?
z
}xi.freeze
SSH_REGEX = %r{
A
(?<source_url>
git@(?<type>github.com|gitlab.com|bitbucket.org):
(?<owner>[w-]+)/(?<name>[w-]+)
(.git)?
)
(#(?<tag>[w-.]+))?
z
}xi.freeze
HTTPS_REGEX = %r{
A
(?<source_url>
https://(?<type>github.com|gitlab.com|bitbucket.org)/
(?<owner>[w-]+)/(?<name>[w-]+)
)
(#(?<tag>[w-.]+))?
z
}xi.freeze
def initialize(uri)
@uri = uri
raise "Required constant REPO_TYPES not defined" unless defined? REPO_TYPES
parse_uri
# debug unless @source_url.nil?
end
def valid_uri?
@uri.end_with?(".git") || @uri.include?("/")
end
def parse_uri
if @uri.end_with? ".git"
@type = REPO_TYPES[:custom]
return
end
repo = match_repo_info
return nil if repo.nil?
@owner = repo[:owner]
@name = repo[:name]
@tag = repo[:tag]
@source_url = make_source_url repo
end
def match_repo_info
[PREFIX_REGEX, SSH_REGEX, HTTPS_REGEX].each do |regex|
repo_matches = regex.match @uri
unless repo_matches.nil?
@type = find_repo_type repo_matches[:type]
return repo_matches
end
end
nil
end
def find_repo_type(type)
REPO_TYPES.each do |_, repo_type|
return repo_type if repo_type.id? type
end
REPO_TYPES[:github]
end
def make_source_url(repo)
return repo[:source_url] if repo.names.include? "source_url"
source_url = @type.full_url || @uri
"#{source_url}/#{@owner}/#{@name}"
end
def download_command(output_folder=nil)
tag_spec = @tag.nil? ? "" : "--branch #{@tag}"
parts = [
"git clone --quiet --depth 1",
tag_spec,
@source_url,
output_folder || @name,
]
parts.join " "
end
def debug
puts ""
puts "source_url: #{@source_url}" unless @source_url.nil?
puts "owner: #{@owner}" unless @owner.nil?
puts "name: #{@name}" unless @name.nil?
puts "tag: #{@tag}" unless @tag.nil?
puts "download cmd: #{download_command}"
end
end
tests.rb
VALID = %w[
user1/repo1
github:user2/repo2
git@github.com:user3/repo3
https://github.com/rmccue/test-repository
gitlab:user5/repo5
git@gitlab.com:user6/repo6
https://gitlab.com/user7/repo7
bitbucket:user8/repo8
git@bitbucket.org:user9/repo9
https://bitbucket.org/user0/repo0
].freeze
INVALID = %w[
http://github.com/user1/repo1
https://github.com/user2
https://github.comuser3/repo3
].freeze
WITH_TAG = %w[
user1/repo1#dev
user2/repo2#v1.2.3
user3/repo3#1234abcd
].freeze
WITH_GIT_SUFFIX = %w[
https://github.com/Rich-Harris/degit.git
user@host:~/repos/website.nl.git
].freeze
def pf(str)
print str
$stdout.flush
end
def run_tests
pf " VALID: "
VALID.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't valid" if repo.type.nil?
end
puts ""
pf " INVALID: "
INVALID.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't invalid" unless repo.type.nil?
end
puts ""
pf " WITH_TAG: "
WITH_TAG.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't valid" if repo.type.nil?
raise "#{r} has no tag" if repo.tag.nil?
end
puts ""
pf "WITH_GIT_SUFFIX: "
WITH_GIT_SUFFIX.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't valid" if repo.type.nil?
end
puts ""
end
beginner ruby console git
$endgroup$
add a comment |
$begingroup$
Coming from Python, JavaScript and PHP, I'd like to learn to write Ruby in the way it's "supposed to". Well-written Python code is called "Pythonic", so I'd like to know how idiomatic my Ruby code is.
I've had great help from Rubocop, slapping my face if I didn't write properly, but I still feel some things can be done better.
Application
This set of scripts downloads a github/gitlab/bitbucket repository, removes the .git folder and moves it to the specified folder, so that the files are "de-git".
Some commands:
# Run tests (for regexes)
./degit.rb --test
# Extract repo to folder with repo name
./degit.rb zpqrtbnk/test-repo
# Extract tag/branch of repo to folder with repo name
./degit.rb zpqrtbnk/test-repo#temp
# Extract repo to specified folder
./degit.rb zpqrtbnk/test-repo some-folder
Code
Ruby v2.4.5
Idea came from degit by Rich Harris
degit.rb
#!/usr/bin/env ruby
require "tmpdir"
require_relative "repo"
require_relative "repo_type"
REPO_TYPES = {
github: RepoType.new("github", "https://github.com", "github.com"),
gitlab: RepoType.new("gitlab", "https://gitlab.com", "gitlab.com"),
bitbucket: RepoType.new("bitbucket", "https://bitbucket.org", "bitbucket.org"),
custom: RepoType.new("custom", :custom, :custom),
}.freeze
# TODO: Error handling
def main
repo_name = ARGV[0]
folder_name = ARGV[1]
raise "Required parameter repo name not specified" if repo_name.nil?
if repo_name == "--test"
require_relative "tests"
run_tests
return
end
degit repo_name, folder_name
end
def temp_dir
dir = Dir.mktmpdir("degit-", "/tmp")
at_exit { FileUtils.remove_entry(dir) }
dir
end
def degit(repo_name, folder_name)
repo = Repo.new repo_name
folder_name ||= repo.name
dest_dir = File.join Dir.pwd, folder_name
dir_exists = Dir.exist? dest_dir
if dir_exists
abort "Aborted" unless confirm_overwrite dest_dir
end
dir = temp_dir
tmp_repo_path = File.join(dir, folder_name)
cmd = repo.download_command tmp_repo_path
puts `#{cmd}`
FileUtils.remove_entry File.join(tmp_repo_path, ".git")
FileUtils.remove_entry dest_dir if dir_exists
FileUtils.mv(tmp_repo_path, Dir.pwd, force: true)
end
def confirm_overwrite(dest_dir)
print "Destination folder #{dest_dir} already exists. Overwrite folder? [y/n] "
# ARGV interferes with gets, so use STDIN.gets
input = STDIN.gets.chomp.downcase
return (input == "y") if %w[y n].include? input
# Continue to ask until input is either y or n
confirm_overwrite dest_dir
end
main if $PROGRAM_NAME == __FILE__
repo_type.rb
class RepoType
attr_reader :name, :full_url
def initialize(name, full_url, base_url, short_code=nil)
@name = name
@full_url = full_url
@base_url = base_url
@short_code = short_code || name.to_s.downcase
end
def id?(id)
[@short_code, @base_url].include? id
end
end
repo.rb
class Repo
attr_reader :type, :tag, :name
PREFIX_REGEX = %r{
A
((?<type>github|gitlab|bitbucket):)?
(?<owner>[w-]+)/(?<name>[w-]+)
(#(?<tag>[w-.]+))?
z
}xi.freeze
SSH_REGEX = %r{
A
(?<source_url>
git@(?<type>github.com|gitlab.com|bitbucket.org):
(?<owner>[w-]+)/(?<name>[w-]+)
(.git)?
)
(#(?<tag>[w-.]+))?
z
}xi.freeze
HTTPS_REGEX = %r{
A
(?<source_url>
https://(?<type>github.com|gitlab.com|bitbucket.org)/
(?<owner>[w-]+)/(?<name>[w-]+)
)
(#(?<tag>[w-.]+))?
z
}xi.freeze
def initialize(uri)
@uri = uri
raise "Required constant REPO_TYPES not defined" unless defined? REPO_TYPES
parse_uri
# debug unless @source_url.nil?
end
def valid_uri?
@uri.end_with?(".git") || @uri.include?("/")
end
def parse_uri
if @uri.end_with? ".git"
@type = REPO_TYPES[:custom]
return
end
repo = match_repo_info
return nil if repo.nil?
@owner = repo[:owner]
@name = repo[:name]
@tag = repo[:tag]
@source_url = make_source_url repo
end
def match_repo_info
[PREFIX_REGEX, SSH_REGEX, HTTPS_REGEX].each do |regex|
repo_matches = regex.match @uri
unless repo_matches.nil?
@type = find_repo_type repo_matches[:type]
return repo_matches
end
end
nil
end
def find_repo_type(type)
REPO_TYPES.each do |_, repo_type|
return repo_type if repo_type.id? type
end
REPO_TYPES[:github]
end
def make_source_url(repo)
return repo[:source_url] if repo.names.include? "source_url"
source_url = @type.full_url || @uri
"#{source_url}/#{@owner}/#{@name}"
end
def download_command(output_folder=nil)
tag_spec = @tag.nil? ? "" : "--branch #{@tag}"
parts = [
"git clone --quiet --depth 1",
tag_spec,
@source_url,
output_folder || @name,
]
parts.join " "
end
def debug
puts ""
puts "source_url: #{@source_url}" unless @source_url.nil?
puts "owner: #{@owner}" unless @owner.nil?
puts "name: #{@name}" unless @name.nil?
puts "tag: #{@tag}" unless @tag.nil?
puts "download cmd: #{download_command}"
end
end
tests.rb
VALID = %w[
user1/repo1
github:user2/repo2
git@github.com:user3/repo3
https://github.com/rmccue/test-repository
gitlab:user5/repo5
git@gitlab.com:user6/repo6
https://gitlab.com/user7/repo7
bitbucket:user8/repo8
git@bitbucket.org:user9/repo9
https://bitbucket.org/user0/repo0
].freeze
INVALID = %w[
http://github.com/user1/repo1
https://github.com/user2
https://github.comuser3/repo3
].freeze
WITH_TAG = %w[
user1/repo1#dev
user2/repo2#v1.2.3
user3/repo3#1234abcd
].freeze
WITH_GIT_SUFFIX = %w[
https://github.com/Rich-Harris/degit.git
user@host:~/repos/website.nl.git
].freeze
def pf(str)
print str
$stdout.flush
end
def run_tests
pf " VALID: "
VALID.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't valid" if repo.type.nil?
end
puts ""
pf " INVALID: "
INVALID.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't invalid" unless repo.type.nil?
end
puts ""
pf " WITH_TAG: "
WITH_TAG.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't valid" if repo.type.nil?
raise "#{r} has no tag" if repo.tag.nil?
end
puts ""
pf "WITH_GIT_SUFFIX: "
WITH_GIT_SUFFIX.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't valid" if repo.type.nil?
end
puts ""
end
beginner ruby console git
$endgroup$
Coming from Python, JavaScript and PHP, I'd like to learn to write Ruby in the way it's "supposed to". Well-written Python code is called "Pythonic", so I'd like to know how idiomatic my Ruby code is.
I've had great help from Rubocop, slapping my face if I didn't write properly, but I still feel some things can be done better.
Application
This set of scripts downloads a github/gitlab/bitbucket repository, removes the .git folder and moves it to the specified folder, so that the files are "de-git".
Some commands:
# Run tests (for regexes)
./degit.rb --test
# Extract repo to folder with repo name
./degit.rb zpqrtbnk/test-repo
# Extract tag/branch of repo to folder with repo name
./degit.rb zpqrtbnk/test-repo#temp
# Extract repo to specified folder
./degit.rb zpqrtbnk/test-repo some-folder
Code
Ruby v2.4.5
Idea came from degit by Rich Harris
degit.rb
#!/usr/bin/env ruby
require "tmpdir"
require_relative "repo"
require_relative "repo_type"
REPO_TYPES = {
github: RepoType.new("github", "https://github.com", "github.com"),
gitlab: RepoType.new("gitlab", "https://gitlab.com", "gitlab.com"),
bitbucket: RepoType.new("bitbucket", "https://bitbucket.org", "bitbucket.org"),
custom: RepoType.new("custom", :custom, :custom),
}.freeze
# TODO: Error handling
def main
repo_name = ARGV[0]
folder_name = ARGV[1]
raise "Required parameter repo name not specified" if repo_name.nil?
if repo_name == "--test"
require_relative "tests"
run_tests
return
end
degit repo_name, folder_name
end
def temp_dir
dir = Dir.mktmpdir("degit-", "/tmp")
at_exit { FileUtils.remove_entry(dir) }
dir
end
def degit(repo_name, folder_name)
repo = Repo.new repo_name
folder_name ||= repo.name
dest_dir = File.join Dir.pwd, folder_name
dir_exists = Dir.exist? dest_dir
if dir_exists
abort "Aborted" unless confirm_overwrite dest_dir
end
dir = temp_dir
tmp_repo_path = File.join(dir, folder_name)
cmd = repo.download_command tmp_repo_path
puts `#{cmd}`
FileUtils.remove_entry File.join(tmp_repo_path, ".git")
FileUtils.remove_entry dest_dir if dir_exists
FileUtils.mv(tmp_repo_path, Dir.pwd, force: true)
end
def confirm_overwrite(dest_dir)
print "Destination folder #{dest_dir} already exists. Overwrite folder? [y/n] "
# ARGV interferes with gets, so use STDIN.gets
input = STDIN.gets.chomp.downcase
return (input == "y") if %w[y n].include? input
# Continue to ask until input is either y or n
confirm_overwrite dest_dir
end
main if $PROGRAM_NAME == __FILE__
repo_type.rb
class RepoType
attr_reader :name, :full_url
def initialize(name, full_url, base_url, short_code=nil)
@name = name
@full_url = full_url
@base_url = base_url
@short_code = short_code || name.to_s.downcase
end
def id?(id)
[@short_code, @base_url].include? id
end
end
repo.rb
class Repo
attr_reader :type, :tag, :name
PREFIX_REGEX = %r{
A
((?<type>github|gitlab|bitbucket):)?
(?<owner>[w-]+)/(?<name>[w-]+)
(#(?<tag>[w-.]+))?
z
}xi.freeze
SSH_REGEX = %r{
A
(?<source_url>
git@(?<type>github.com|gitlab.com|bitbucket.org):
(?<owner>[w-]+)/(?<name>[w-]+)
(.git)?
)
(#(?<tag>[w-.]+))?
z
}xi.freeze
HTTPS_REGEX = %r{
A
(?<source_url>
https://(?<type>github.com|gitlab.com|bitbucket.org)/
(?<owner>[w-]+)/(?<name>[w-]+)
)
(#(?<tag>[w-.]+))?
z
}xi.freeze
def initialize(uri)
@uri = uri
raise "Required constant REPO_TYPES not defined" unless defined? REPO_TYPES
parse_uri
# debug unless @source_url.nil?
end
def valid_uri?
@uri.end_with?(".git") || @uri.include?("/")
end
def parse_uri
if @uri.end_with? ".git"
@type = REPO_TYPES[:custom]
return
end
repo = match_repo_info
return nil if repo.nil?
@owner = repo[:owner]
@name = repo[:name]
@tag = repo[:tag]
@source_url = make_source_url repo
end
def match_repo_info
[PREFIX_REGEX, SSH_REGEX, HTTPS_REGEX].each do |regex|
repo_matches = regex.match @uri
unless repo_matches.nil?
@type = find_repo_type repo_matches[:type]
return repo_matches
end
end
nil
end
def find_repo_type(type)
REPO_TYPES.each do |_, repo_type|
return repo_type if repo_type.id? type
end
REPO_TYPES[:github]
end
def make_source_url(repo)
return repo[:source_url] if repo.names.include? "source_url"
source_url = @type.full_url || @uri
"#{source_url}/#{@owner}/#{@name}"
end
def download_command(output_folder=nil)
tag_spec = @tag.nil? ? "" : "--branch #{@tag}"
parts = [
"git clone --quiet --depth 1",
tag_spec,
@source_url,
output_folder || @name,
]
parts.join " "
end
def debug
puts ""
puts "source_url: #{@source_url}" unless @source_url.nil?
puts "owner: #{@owner}" unless @owner.nil?
puts "name: #{@name}" unless @name.nil?
puts "tag: #{@tag}" unless @tag.nil?
puts "download cmd: #{download_command}"
end
end
tests.rb
VALID = %w[
user1/repo1
github:user2/repo2
git@github.com:user3/repo3
https://github.com/rmccue/test-repository
gitlab:user5/repo5
git@gitlab.com:user6/repo6
https://gitlab.com/user7/repo7
bitbucket:user8/repo8
git@bitbucket.org:user9/repo9
https://bitbucket.org/user0/repo0
].freeze
INVALID = %w[
http://github.com/user1/repo1
https://github.com/user2
https://github.comuser3/repo3
].freeze
WITH_TAG = %w[
user1/repo1#dev
user2/repo2#v1.2.3
user3/repo3#1234abcd
].freeze
WITH_GIT_SUFFIX = %w[
https://github.com/Rich-Harris/degit.git
user@host:~/repos/website.nl.git
].freeze
def pf(str)
print str
$stdout.flush
end
def run_tests
pf " VALID: "
VALID.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't valid" if repo.type.nil?
end
puts ""
pf " INVALID: "
INVALID.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't invalid" unless repo.type.nil?
end
puts ""
pf " WITH_TAG: "
WITH_TAG.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't valid" if repo.type.nil?
raise "#{r} has no tag" if repo.tag.nil?
end
puts ""
pf "WITH_GIT_SUFFIX: "
WITH_GIT_SUFFIX.each do |r|
pf "."
repo = Repo.new r
raise "#{r} isn't valid" if repo.type.nil?
end
puts ""
end
beginner ruby console git
beginner ruby console git
edited Feb 1 at 7:20
Richard de Wit
asked Jan 31 at 15:28
Richard de WitRichard de Wit
1164
1164
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
$begingroup$
Ruby does not have an import system like python, so variables and methods at the top level like REPO_TYPES
and temp_dir
are effectively global variables and methods.
Use modules to aggressively namespace, even for your main
, especially when a small script begins to span more than one file:
module Degit
def self.main # define singleton method
end
end
Degit.main # call singleton method
This is also true for methods as well. def self.main
in the example defines a singleton method on Degit
itself. (Degit
is a singleton in the sense that it will be the only instance of Module
named "Degit", and main
is a method it will now have).
Ruby classes operate in the same way:
class Foo
class << self # opens singleton context
def foo # also defines a singleton method
end
end
end
On another note, I feel like RepoType
should either be:
- completely removed and its responsibilities handled by
Repo
Or
- named
Host
and be more cohesive by owning variables and methodsREPO_TYPE
andfind_repo_type
within it, along with the regex definitions associated with eachHost
Here's an example combining what I've outlined above:
class Host
class << self
def all
@all ||= {} # the `Host` singleton is an instance of `Class`, and can have @vars!
end
def ssh_regex(hostname)
/blahblah#{hostname}blahblah/
end
end
def initialize(name, hostname)
@name = name
@host_uri = URI("http://www.#{hostname}")
end
end
```
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f212632%2fdownload-a-git-repo-without-git-folder%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
Ruby does not have an import system like python, so variables and methods at the top level like REPO_TYPES
and temp_dir
are effectively global variables and methods.
Use modules to aggressively namespace, even for your main
, especially when a small script begins to span more than one file:
module Degit
def self.main # define singleton method
end
end
Degit.main # call singleton method
This is also true for methods as well. def self.main
in the example defines a singleton method on Degit
itself. (Degit
is a singleton in the sense that it will be the only instance of Module
named "Degit", and main
is a method it will now have).
Ruby classes operate in the same way:
class Foo
class << self # opens singleton context
def foo # also defines a singleton method
end
end
end
On another note, I feel like RepoType
should either be:
- completely removed and its responsibilities handled by
Repo
Or
- named
Host
and be more cohesive by owning variables and methodsREPO_TYPE
andfind_repo_type
within it, along with the regex definitions associated with eachHost
Here's an example combining what I've outlined above:
class Host
class << self
def all
@all ||= {} # the `Host` singleton is an instance of `Class`, and can have @vars!
end
def ssh_regex(hostname)
/blahblah#{hostname}blahblah/
end
end
def initialize(name, hostname)
@name = name
@host_uri = URI("http://www.#{hostname}")
end
end
```
$endgroup$
add a comment |
$begingroup$
Ruby does not have an import system like python, so variables and methods at the top level like REPO_TYPES
and temp_dir
are effectively global variables and methods.
Use modules to aggressively namespace, even for your main
, especially when a small script begins to span more than one file:
module Degit
def self.main # define singleton method
end
end
Degit.main # call singleton method
This is also true for methods as well. def self.main
in the example defines a singleton method on Degit
itself. (Degit
is a singleton in the sense that it will be the only instance of Module
named "Degit", and main
is a method it will now have).
Ruby classes operate in the same way:
class Foo
class << self # opens singleton context
def foo # also defines a singleton method
end
end
end
On another note, I feel like RepoType
should either be:
- completely removed and its responsibilities handled by
Repo
Or
- named
Host
and be more cohesive by owning variables and methodsREPO_TYPE
andfind_repo_type
within it, along with the regex definitions associated with eachHost
Here's an example combining what I've outlined above:
class Host
class << self
def all
@all ||= {} # the `Host` singleton is an instance of `Class`, and can have @vars!
end
def ssh_regex(hostname)
/blahblah#{hostname}blahblah/
end
end
def initialize(name, hostname)
@name = name
@host_uri = URI("http://www.#{hostname}")
end
end
```
$endgroup$
add a comment |
$begingroup$
Ruby does not have an import system like python, so variables and methods at the top level like REPO_TYPES
and temp_dir
are effectively global variables and methods.
Use modules to aggressively namespace, even for your main
, especially when a small script begins to span more than one file:
module Degit
def self.main # define singleton method
end
end
Degit.main # call singleton method
This is also true for methods as well. def self.main
in the example defines a singleton method on Degit
itself. (Degit
is a singleton in the sense that it will be the only instance of Module
named "Degit", and main
is a method it will now have).
Ruby classes operate in the same way:
class Foo
class << self # opens singleton context
def foo # also defines a singleton method
end
end
end
On another note, I feel like RepoType
should either be:
- completely removed and its responsibilities handled by
Repo
Or
- named
Host
and be more cohesive by owning variables and methodsREPO_TYPE
andfind_repo_type
within it, along with the regex definitions associated with eachHost
Here's an example combining what I've outlined above:
class Host
class << self
def all
@all ||= {} # the `Host` singleton is an instance of `Class`, and can have @vars!
end
def ssh_regex(hostname)
/blahblah#{hostname}blahblah/
end
end
def initialize(name, hostname)
@name = name
@host_uri = URI("http://www.#{hostname}")
end
end
```
$endgroup$
Ruby does not have an import system like python, so variables and methods at the top level like REPO_TYPES
and temp_dir
are effectively global variables and methods.
Use modules to aggressively namespace, even for your main
, especially when a small script begins to span more than one file:
module Degit
def self.main # define singleton method
end
end
Degit.main # call singleton method
This is also true for methods as well. def self.main
in the example defines a singleton method on Degit
itself. (Degit
is a singleton in the sense that it will be the only instance of Module
named "Degit", and main
is a method it will now have).
Ruby classes operate in the same way:
class Foo
class << self # opens singleton context
def foo # also defines a singleton method
end
end
end
On another note, I feel like RepoType
should either be:
- completely removed and its responsibilities handled by
Repo
Or
- named
Host
and be more cohesive by owning variables and methodsREPO_TYPE
andfind_repo_type
within it, along with the regex definitions associated with eachHost
Here's an example combining what I've outlined above:
class Host
class << self
def all
@all ||= {} # the `Host` singleton is an instance of `Class`, and can have @vars!
end
def ssh_regex(hostname)
/blahblah#{hostname}blahblah/
end
end
def initialize(name, hostname)
@name = name
@host_uri = URI("http://www.#{hostname}")
end
end
```
answered 12 mins ago
KacheKache
20615
20615
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f212632%2fdownload-a-git-repo-without-git-folder%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown