mirror of
https://github.com/KevinMidboe/linguist.git
synced 2025-10-29 17:50:22 +00:00
181 lines
4.5 KiB
Ruby
Executable File
181 lines
4.5 KiB
Ruby
Executable File
#!/usr/bin/env ruby
|
|
|
|
require "optparse"
|
|
require "open3"
|
|
|
|
class GrammarRepo
|
|
|
|
# Whitelist of trusted hosting providers
|
|
HOSTS = Regexp.union %w[github.com bitbucket.org gitlab.com]
|
|
|
|
# Public: Define a repository source by upstream URL.
|
|
#
|
|
# url - an HTTPS, HTTP, or SSH address accepted by git-remote(1)
|
|
# Only domains listed in HOSTS are accepted; unrecognised
|
|
# hostnames or invalid URLs will raise an ArgumentError.
|
|
#
|
|
# Assumption: Repo URLs will never include subdomains.
|
|
# We only check for a possible `www`, nothing else.
|
|
#
|
|
# module_path - path of submodule as registered in `.gitmodules`
|
|
# Omit this unless grammar is being replaced.
|
|
def initialize(url, module_path = nil)
|
|
if https? url
|
|
@host = $1.downcase
|
|
@user = $2
|
|
@repo = $3.sub /\.git$/, ""
|
|
elsif ssh?(url) || shorthand?(url)
|
|
@host = $1.downcase
|
|
@user = $2
|
|
@repo = $3
|
|
elsif implicit_shorthand? url
|
|
@host = "github.com"
|
|
@user = $1
|
|
@repo = $2
|
|
else
|
|
raise ArgumentError, "Unsupported URL: #{url}"
|
|
end
|
|
end
|
|
|
|
# Match a well-formed HTTP or HTTPS address
|
|
def https?(url)
|
|
nil unless url =~ /
|
|
^ (?<protocol> https? ://)?
|
|
(?<userauth> [^@.]+ @ )?
|
|
(?<subdomain> www \. )?
|
|
(?<hostname> #{HOSTS} )
|
|
\/ (?<user> [^\/]+ )
|
|
\/ (?<repo> [^\/]+ ) /xi
|
|
end
|
|
|
|
# Match an SSH address starting with `git@`
|
|
def ssh?(url)
|
|
nil unless url =~ /
|
|
^ git@
|
|
(?<hostname> #{HOSTS}) :
|
|
(?<user> [^\/]+) \/
|
|
(?<repo> [^\/]+) \.git $/xi
|
|
end
|
|
|
|
# Match `provider:user/repo`
|
|
def shorthand?(url)
|
|
nil unless url =~ /
|
|
^ (?<hostname> #{HOSTS}) : \/?
|
|
(?<user> [^\/]+) \/
|
|
(?<repo> [^\/]+) \/? $ /xi
|
|
end
|
|
|
|
# Match `user/repo` shorthand, assumed to be GitHub
|
|
def implicit_shorthand?(url)
|
|
nil unless url =~ /
|
|
^ \/? (?<user>[^\/]+)
|
|
\/ (?<repo>[^\/]+)
|
|
\/? $/xi
|
|
end
|
|
end
|
|
|
|
|
|
class GrammarGuardian
|
|
|
|
ROOT = File.expand_path("../../", __FILE__)
|
|
|
|
def initialize
|
|
# Track each change so we can roll back after a failed command
|
|
@changes = Hash.new
|
|
end
|
|
|
|
# Print debugging feedback to STDOUT if running with --verbose
|
|
def log(msg)
|
|
puts msg if $verbose
|
|
end
|
|
|
|
def command(*args)
|
|
log "$ #{args.join(' ')}"
|
|
output, status = Open3.capture2e(*args)
|
|
if !status.success?
|
|
output.each_line do |line|
|
|
log " > #{line}"
|
|
end
|
|
warn "Command failed. Aborting."
|
|
exit 1
|
|
end
|
|
end
|
|
end
|
|
|
|
# Isolate the vendor-name component of a submodule path
|
|
def parse_submodule(name)
|
|
name =~ /^(?:.*(?:vendor\/)?grammars\/)?([^\/]+)/i
|
|
path = "vendor/grammars/#{$1}"
|
|
unless File.exist?("#{ROOT}/" + path)
|
|
warn "Submodule '#{path}' does not exist. Aborting."
|
|
exit 1
|
|
end
|
|
path
|
|
end
|
|
|
|
|
|
usage = """Usage:
|
|
#{$0} [-v|--verbose] [--replace grammar] url
|
|
Examples:
|
|
#{$0} https://github.com/Alhadis/language-roff
|
|
#{$0} --replace sublime-apl https://github.com/Alhadis/language-apl
|
|
"""
|
|
|
|
$replace = nil
|
|
$verbose = true
|
|
$compile = false
|
|
|
|
OptionParser.new do |opts|
|
|
opts.banner = usage
|
|
opts.on("-q", "--quiet", "Do not print output unless there's a failure") do
|
|
$verbose = false
|
|
end
|
|
opts.on("-rSUBMODULE", "--replace=SUBMODDULE", "Replace an existing grammar submodule.") do |name|
|
|
$replace = name
|
|
end
|
|
opts.on("-C", "--compile", "Compile grammar using the new grammar-compiler.") do
|
|
$compile = true
|
|
end
|
|
end.parse!
|
|
|
|
|
|
$url = ARGV[0]
|
|
|
|
# No URL? Print a usage message and bail.
|
|
unless $url
|
|
warn usage
|
|
exit 1;
|
|
end
|
|
|
|
# Ensure the given URL is an HTTPS link
|
|
parts = parse_url $url
|
|
https = "https://#{parts[:host]}/#{parts[:user]}/#{parts[:repo]}"
|
|
repo_new = "vendor/grammars/#{parts[:repo]}"
|
|
repo_old = parse_submodule($replace) if $replace
|
|
|
|
Dir.chdir(ROOT)
|
|
|
|
if repo_old
|
|
log "Deregistering: #{repo_old}"
|
|
command('git', 'submodule', 'deinit', repo_old)
|
|
command('git', 'rm', '-rf', repo_old)
|
|
command('script/grammar-compiler', 'update', '-f') if $compile
|
|
end
|
|
|
|
log "Registering new submodule: #{repo_new}"
|
|
command('git', 'submodule', 'add', '-f', https, repo_new)
|
|
command('script/grammar-compiler', 'add', repo_new) if $compile
|
|
|
|
log "Confirming license"
|
|
if repo_old
|
|
command('script/licensed')
|
|
else
|
|
repo_new = File.absolute_path(repo_new)
|
|
command('script/licensed', '--module', repo_new)
|
|
end
|
|
|
|
log "Updating grammar documentation in vendor/README.md"
|
|
command('bundle', 'exec', 'rake', 'samples')
|
|
command('script/sort-submodules')
|
|
command('script/list-grammars')
|