Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite script/add-grammar as a plain shell-script #5521

Merged
merged 7 commits into from
Sep 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ trim_trailing_whitespace = false
indent_style = tab
indent_size = 8

[{Dockerfile,Makefile,*.go}]
[{Dockerfile,Makefile,*.go,script/add-grammar}]
indent_style = tab
indent_size = 4

Expand Down
259 changes: 137 additions & 122 deletions script/add-grammar
Original file line number Diff line number Diff line change
@@ -1,124 +1,139 @@
#!/usr/bin/env ruby

require "optparse"
require "open3"

ROOT = File.expand_path("../../", __FILE__)


# Break a repository URL into its separate components
def parse_url(input)
hosts = "github\.com|bitbucket\.org|gitlab\.com"

# HTTPS/HTTP link pointing to recognised hosts
if input =~ /^(?:https?:\/\/)?(?:[^.@]+@)?(?:www\.)?(#{hosts})\/([^\/]+)\/([^\/]+)/i
{ host: $1.downcase(), user: $2, repo: $3.sub(/\.git$/, "") }
# SSH
elsif input =~ /^git@(#{hosts}):([^\/]+)\/([^\/]+)\.git$/i
{ host: $1.downcase(), user: $2, repo: $3 }
# provider:user/repo
elsif input =~ /^(github|bitbucket|gitlab):\/?([^\/]+)\/([^\/]+)\/?$/i
{ host: $1.downcase(), user: $2, repo: $3 }
# user/repo - Common GitHub shorthand
elsif input =~ /^\/?([^\/]+)\/([^\/]+)\/?$/
{ host: "github.com", user: $1, repo: $2 }
else
raise "Unsupported URL: #{input}"
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

# Print debugging feedback to STDOUT if not running with --quiet
def log(msg)
puts msg if $verbose
end

def command(*args, hide_warnings: false)
log "$ #{args.join(' ')}"
stdout, stderr, status = Open3.capture3(*args)
unless status.success?
output = stdout.strip + "\n" + stderr.strip
output.each_line do |line|
log " > #{line}"
end
warn "Command failed. Aborting."
exit 1
end
return if stderr.empty?

unless hide_warnings
stderr.each_line do |line|
log " > #{line}"
end
end
end

usage = """Usage:
#{$0} [-q|--quiet] [--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

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
end.parse!


$url = ARGV[0]

# No URL? Print a usage message and bail.
unless $url
warn usage
exit 1;
end

# Exit early if docker isn't installed or running.
log "Checking docker is installed and running"
command('docker', 'ps')
#!/bin/sh
lildude marked this conversation as resolved.
Show resolved Hide resolved
# shellcheck disable=SC2006,SC2021
set -e

usage="${0##*/} [-q|--quiet] [--replace submodule] url"
unset replace quiet

# Print non-essential feedback
log()([ "$quiet" ] || printf '%s\n' "$@")

# Print an error message
warn()(printf '%s: %s\n' "${0##*/}" "$@")

# Display a shortened help summary and bail with an error code
bad_invocation(){
printf '%s\n' "$usage" >&2
exit 2
}


# Parse options
while [ -n "$1" ]; do case $1 in

# Print an unabridged usage summary, then exit
-h|--help|-\?)
cat <<-HELP
Usage:
$usage

Options:
-q, --quiet Do not print output unless there's a failure.
-r, --replace SUBMODDULE Replace an existing grammar submodule.

Examples:
$0 https://github.com/Alhadis/language-roff
$0 --replace sublime-apl https://github.com/Alhadis/language-apl
HELP
exit ;;

# Hide non-essential feedback
-q | --quiet)
quiet=1
break ;;

# Replace an existing submodule
-r* | --replace | --replace=*)
case $1 in
-r|--replace) replace=$2; shift ;; # -r [module], --replace [module]
-r*) replace=${1#??} ;; # -r[module]
--replace=*) replace=${1#*=} ;; # --replace=[module]
esac ;;

# Double-dash: Terminate option parsing
--)
shift
break ;;

# Invalid option: abort
--* | -?*)
warn 'invalid option: "%s"' "${0##*/}" "$1" >&2
bad_invocation ;;

# Argument not prefixed with a dash
*) break ;;

esac; shift
done


# Don't proceed any further if we don't have a URL
[ "$1" ] || bad_invocation


# Check upfront that executables we depend on are available
for cmd in docker git sed ruby bundle; do
command -v "$cmd" >/dev/null 2>&1 || {
warn "Required command '$cmd' not found"
warn 'See CONTRIBUTING.md for help on getting started: https://git.io/J0eqy'
exit 1
}
done

# Make sure Docker's running
log 'Checking Docker is installed and running'
docker ps >/dev/null

# Make sure we're running from checkout directory
root=`git rev-parse --git-dir`
lildude marked this conversation as resolved.
Show resolved Hide resolved
root="${root%/.git}"
# shellcheck disable=SC3013
if [ ! "$root" = .git ] && [ -d "$root" ] && ! [ . -ef "$root" ] >/dev/null 2>&1; then
log "Switching directory to $root"
cd "$root"
fi

# 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', hide_warnings: true)
end

log "Registering new submodule: #{repo_new}"
command('git', 'submodule', 'add', '-f', https, repo_new)
command('script/grammar-compiler', 'add', repo_new)

log "Caching grammar license"
command("bundle", "exec", "licensed", "cache", "-c", "vendor/licenses/config.yml")

log "Updating grammar documentation in vendor/README.md"
command('bundle', 'exec', 'rake', 'samples', hide_warnings: true)
command('script/sort-submodules')
command('script/list-grammars')
url=`script/normalise-url --protocol=https "$1"`
lildude marked this conversation as resolved.
Show resolved Hide resolved

# Make sure it's not already registered
path="vendor/grammars/${url##*/}"
path="${path%.git}"
if [ -e "$path" ]; then
warn "Submodule '$path' already exists. Did you forget the '--replace' option?"
warn "Run '$0 --help' for invocation advice"
exit 1
fi

# Remove the old submodule if we're `--replace`ing one
if [ "$replace" ]; then

# Normalise submodule reference
replace=`printf %s "$replace" \
| tr '[A-Z]' '[a-z]' \
| sed 's/^\(.*\/\)\{0,1\}vendor\///; s/^grammars\///'`
lildude marked this conversation as resolved.
Show resolved Hide resolved
replace=`git config --list \
| grep -Fi -m1 "submodule.vendor/grammars/$replace.url=" \
| sed 's/\.url=.*//; s/^submodule\.//' || :`
lildude marked this conversation as resolved.
Show resolved Hide resolved
[ "$replace" ] || {
warn "Submodule '$replace' does not exist. Aborting."
exit 1
}

log "Deregistering submodule: $replace"
git submodule deinit "$replace"
git rm -rf "$replace"
script/grammar-compiler update -f >/dev/null 2>&1
fi

log "Registering new submodule: $url"
git submodule add -f "$url" "$path"
script/grammar-compiler add "$path"

log 'Caching grammar license'
bundle exec licensed cache -c vendor/licenses/config.yml

log 'Updating grammar documentation in vendor/README.md'
bundle exec rake samples >/dev/null 2>&1
script/sort-submodules
script/list-grammars
Loading