Skip to content

Instantly share code, notes, and snippets.

@balupton
Forked from Jarla/gist:840182
Last active September 25, 2015 01:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save balupton/840202 to your computer and use it in GitHub Desktop.
Save balupton/840202 to your computer and use it in GitHub Desktop.
Aloha Editor's Command Line Interface. Attempt #2
#!/usr/bin/env ruby
# == Name
# cli - Aloha Editor's Command Line Interface
#
# == Synopsis
# Refer to the README file for usage
#
# == Options
# -h, --help Displays help message
# -v, --version Display the version, then exit
# -q, --quiet Output as little as possible, overrides verbose
# -V, --verbose Verbose output
#
require 'optparse'
require 'ostruct'
require 'date'
begin
require 'rdoc/usage'
RDOC_INCLUDED = true
rescue LoadError
RDOC_INCLUDED = false
end
class App
# Remotes
REMOTE_ALOHA_URL = 'http://github.com/alohaeditor/Aloha-Editor.git'
REMOTE_ALOHA = 'aloha'
# Versioning
BRANCH_DEV = 'dev'
BRANCH_VERSION = '0.9.4'
BRANCH_MASTER = 'master'
# Building
BUILD_DIR = './.build'
# Uglifiy
UGLIFY_URL = 'https://github.com/mishoo/UglifyJS/raw/master/bin/uglifyjs'
UGLIFY_DIR = './.build/uglify'
UGLIFY_FILE = './.build/uglify/uglify'
# Closure
CLOSURE_URL = 'http://closure-compiler.googlecode.com/files/compiler-latest.zip'
CLOSURE_DIR = './.build/closure'
CLOSURE_ZIP = './.build/closure/compiler.zip'
CLOSURE_FILE = './.build/closure/compiler.jar'
SOURCE_MAP = './scripts/closure.map'
# YUI
YUI_URL = 'http://yuilibrary.com/downloads/yuicompressor/yuicompressor-2.4.2.zip'
YUI_DIR = './.build/yui'
YUI_ZIP = './.build/yui/compiler.zip'
YUI_FILE = './.build/yui/yuicompressor-2.4.2/build/yuicompressor-2.4.2.jar'
# ===========================================================================
# Init Helpers
# Run a Command
def run ( command, output=true )
if command.kind_of?(Array)
result = ""
command.each do |c|
result = result + run(c,output)
end
return result
end
if output
puts command + "\n"
end
result = `#{command}`
if output
puts result
end
return result
end
# Download a File
def download ( url, file )
result = run("curl -L #{url} -o #{file}")
end
# Extract a File
def extract ( dir, file )
file = file.gsub(dir,'.')
result = run(["cd #{dir}","tar -xf #{file}","rm -Rf #{file}"])
end
# ===========================================================================
# Init Commands
# Initialise our CLI
def initialize
init_env
end
# Initialise our Environment
def init_env
# Check for Requirements
reqs = ['mkdir','curl','tar','git','ant','rm','mv','java']
reqs.each do |req|
has_req = run("which #{req}",false).strip
if has_req.empty?
abort("CLI requires the following binary which is not installed: #{req}")
end
end
# Do not care for compilation yet
return
# Check for Closure Compiler
if !File.exists?(CLOSURE_FILE)
run("mkdir -p #{CLOSURE_DIR}")
puts "Downloading the Closure Compiler..."
download(CLOSURE_URL, CLOSURE_ZIP)
extract(CLOSURE_DIR, CLOSURE_ZIP)
run("chmod +x #{CLOSURE_FILE}")
end
# Check for Uglify
if !File.exists?(UGLIFY_FILE)
run("mkdir -p #{UGLIFY_DIR}")
puts "Downloading the Uglify Compiler..."
download(UGLIFY_URL, UGLIFY_FILE)
run("chmod +x #{UGLIFY_FILE}")
end
# Check for YUI Compiler
if !File.exists?(YUI_FILE)
run("mkdir -p #{YUI_DIR}")
puts "Downloading the YUI Compiler..."
download(YUI_URL, (YUI_ZIP))
extract(YUI_DIR, YUI_ZIP)
run("chmod +x #{YUI_FILE}")
end
end
# ===========================================================================
# Build Helpers
def compressCss ( in_file, out_file )
# Calculate
in_file_size = File.size(in_file)
# Handle
if in_file.equal? out_file
out_file = out_file.gsub(/\.js$/, '.min.js')
compressCssWithYui(in_file,out_file)
run("rm #{in_file}")
run("mv #{out_file} #{in_file}")
out_file = in_file
else
compressCssWithYui(in_file,out_file)
out_file_size = File.size(out_file)
end
# Calculate
out_file_size = File.size(out_file)
ratio = Float(out_file_size)/Float(in_file_size)
reduction = ((1-ratio)*100).round
# Log
puts "Compressed the file [#{in_file}] to [#{out_file}] with a #{reduction}% reduction"
end
def compressJs ( in_file, out_file )
# Calculate
in_file_size = File.size(in_file)
# Handle
if in_file.equal? out_file
out_file = out_file.gsub(/\.js$/, '.min.js')
compressJsWithUglify(in_file,out_file)
run("rm #{in_file}")
run("mv #{out_file} #{in_file}")
out_file = in_file
else
compressJsWithUglify(in_file,out_file)
out_file_size = File.size(out_file)
end
# Calculate
out_file_size = File.size(out_file)
ratio = Float(out_file_size)/Float(in_file_size)
reduction = ((1-ratio)*100).round
# Log
puts "Compressed the file [#{in_file}] to [#{out_file}] with a #{reduction}% reduction"
end
# Compress a CSS File with YUI
def compressCssWithYui ( in_file, out_file )
result = run("java -jar #{YUI_FILE} --type css -o #{out_file} --charset UTF-8 #{in_file}")
end
# Compress a Javascript File with Uglify
def compressJsWithUglify ( in_file, out_file )
result = run("#{UGLIFY_FILE} -o #{out_file} #{in_file}")
end
# Compress a Javascript file with Closure
def compressJsWithClosure ( in_file, out_file )
result = run("java -jar #{CLOSURE_FILE} --js_output_file=#{out_file} --js=#{in_file}")
end
# ===========================================================================
# Git Helpers
# Aborts if Changes are Found
def has_changes
result = run("git status")
if result.include? 'Changed but not updated'
abort("You have un-committed changes that need to be committed before we can proceed.\n#{result}")
end
end
# Check if a Branch Exists
def branch_exists(branch)
branches = run("git branch")
regex = Regexp.new('[\\n\\s\\*]+' + Regexp.escape(branch) + '\\n')
result = ((branches =~ regex) ? true : false)
return result
end
# Check if a Branch Exists
def remote_branch_exists(branch)
branches = run("git branch -all")
regex = Regexp.new('\\/' + Regexp.escape(branch) + '\\n')
result = ((branches =~ regex) ? true : false)
return result
end
# Checkout a Branch
def checkout(branch)
if branch_exists(branch)
run("git checkout #{branch}")
else
if remote_branch_exists(branch)
run("git checkout -b #{branch} #{REMOTE_ALOHA}/#{branch}")
else
run("git branch #{branch} #{BRANCH_MASTER}")
end
end
end
# Check if a Remote Exists
def remote_exists(remote)
remotes = run("git remote")
regex = Regexp.new('[\\n\\s\\*]+' + Regexp.escape(remote) + '\\n')
result = ((remotes =~ regex) ? true : false)
return result
end
# Add a Remote
def remote_add(url,name)
unless remote_exists(name)
run(["git remote add #{name} #{url}","git fetch"])
end
end
# Merge a Branch In
def merge(branch)
run("git merge #{branch}")
end
# Stage Known Files
def add
run("git add -u")
end
# Push to Origin
def push
run("git push origin --all")
end
# Pull From Everywhere
def pull
run("git pull --all")
end
# ===========================================================================
# Git Handlers
# ---------------------------------------------------------------------------
# Checkout
# Checkout Version Branch
def version
checkout(BRANCH_VERSION)
end
# Checkout Dev Branch
def dev
checkout(BRANCH_DEV)
end
# Checkout Master Branch
def master
checkout(BRANCH_MASTER)
end
# ---------------------------------------------------------------------------
# Branch
# Update Branch
def update_branch(branch)
checkout(branch)
update
end
# ---------------------------------------------------------------------------
# Branches
# Initialise Branches
def init_branches
remote_add(REMOTE_ALOHA_URL,REMOTE_ALOHA)
master
version
dev
end
# Update Branches
def update_branches
update_branch(BRANCH_MASTER)
update_branch(BRANCH_VERSION)
update_branch(BRANCH_DEV)
end
# ---------------------------------------------------------------------------
# Submodules
# Initialise Submodules
def init_submodules
run([
"git submodule init",
"git submodule update",
"git submodule foreach --recursive 'git reset --hard ; git branch -D dev ; git checkout -b dev origin/dev ; git checkout master ; git submodule init ; git submodule update --merge'"
])
end
# Update Submodules
def update_submodules
run([
"git submodule init",
"git submodule update --merge",
"git submodule foreach 'git submodule init; git submodule update --merge'"
])
end
# Upgrade Submodules
def upgrade_submodules
run([
"git submodule init",
"git submodule update --merge",
"git submodule foreach 'git checkout master; git pull --all'"
])
end
# ---------------------------------------------------------------------------
# Utility
# Give Birth to a New Aloha Editor
def birth
puts "Welcome to the Aloha Editor CLI.\nWhat is your repository URL? E.g. git@github.com:balupton/Aloha-Editor.git"
url = gets.chomp.strip
run("git init")
remote_add(url,"origin")
install
end
# Install Aloha Editor
def install
init_branches
init_submodules
update_branches
end
# Update
def update
pull
update_submodules
end
# Upgrade Aloha Editor
def upgrade
pull
upgrade_submodules
end
# Build Aloha Editor
def build
run(["cd build","ant build","cd .."])
end
# ---------------------------------------------------------------------------
# Deploy
# Deploy the Changes From Master to Version + Dev
def deploy_from_master
version
merge(BRANCH_MASTER)
dev
merge(BRANCH_MASTER)
master
push
end
# Deploy the Changes From Dev to Version + Master
def deploy_from_dev
version
merge(BRANCH_DEV)
master
merge(BRANCH_DEV)
dev
push
end
end
# ===========================================================================
# Booter
class Booter
VERSION = :'0.0.1'
attr_reader :options
def initialize(arguments, stdin)
@arguments = arguments
@stdin = stdin
# Set defaults
@options = OpenStruct.new
@options.verbose = false
@options.quiet = false
# TO DO - add additional defaults
end
# Parse options, check arguments, then process the command
def run
if parsed_options? && arguments_valid?
puts "Start at #{DateTime.now}\n\n" if @options.verbose
output_options if @options.verbose # [Optional]
process_arguments
process_command
puts "\nFinished at #{DateTime.now}" if @options.verbose
else
output_usage
end
end
protected
# Parse options
def parsed_options?
# Specify options
opts = OptionParser.new
opts.on('-v', '--version') { output_version ; exit 0 }
opts.on('-h', '--help') { output_help }
opts.on('-V', '--verbose') { @options.verbose = true }
opts.on('-q', '--quiet') { @options.quiet = true }
# TO DO - add additional options
opts.parse!(@arguments) rescue return false
process_options
true
end
# Performs post-parse processing on options
def process_options
@options.verbose = false if @options.quiet
end
def output_options
puts :"Options:\n"
@options.marshal_dump.each do |name, val|
puts " #{name} = #{val}"
end
end
# True if required arguments were provided
def arguments_valid?
# TO DO - implement your real logic here
true if @arguments.length == 1
end
# Setup the arguments
def process_arguments
# TO DO - place in local vars, etc
end
def output_help
output_version
if RDOC_INCLUDED
RDoc::usage() #exits app
else
puts "No RDoc"
end
end
def output_usage
if RDOC_INCLUDED
RDoc::usage(:'usage') # gets usage from comments above
else
puts "No RDoc"
end
end
def output_version
puts "#{File.basename(__FILE__)} version #{VERSION}"
end
def process_command
# Create Application
app = App.new
# Fetch + Execute
command = @arguments[0].gsub('-','_')
unless app.respond_to?(command)
abort("Unknown command: #{command}")
end
app.send(command)
end
def process_standard_input
input = @stdin.read
# TO DO - process input
# [Optional]
#@stdin.each do |line|
# # TO DO - process each line
#end
end
end
# Create Booter
booter = Booter.new(ARGV, STDIN)
booter.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment