lib/sub/app.rb in sub-0.3.0 vs lib/sub/app.rb in sub-0.4.0
- old
+ new
@@ -1,120 +1,178 @@
#!/usr/local/bin/ruby
require 'benchmark'
require 'fileutils'
+require 'sub/sys'
-QUIET = 0
-NORMAL = 1
-VERBOSE = 2
-
class Sub
+ include Sys::Client
+
DEFAULT_BASE_URL = "svn+ssh://rubyforge.org/var/svn"
def self.from_args(args)
- verbosity = NORMAL
still_parsing_options = true
- command = :up
+ command = defaults[:command]
options = {}
- while still_parsing_options
+ real_args = []
+ while !args.empty?
case args[0]
- when 'up', 'co', 'help'
+
+ # commands
+ when 'up', 'co', 'help', 'ext', 'ignore'
options[:command] = args[0]
+
+ # no-param options
+ when '--version'
+ puts "Sub version #{Sub::VERSION::STRING}"
+ exit 0
when '-v', '--verbose'
options[:verbosity] = VERBOSE
when '-q', '--quiet'
options[:verbosity] = QUIET
when '-h', '--help'
options[:command] = 'help'
still_parsing_options = false
when '-c', '--clean'
options[:clean] = true
+
+ # one-param options
when '--url'
args.shift
options[:url] = args[0]
- when '--version'
- puts "Sub version #{Sub::VERSION::STRING}"
- exit 0
+ when '--revision', '-r'
+ args.shift
+ options[:revision] = args[0]
+ when '--directory', '--dir', '-d'
+ args.shift
+ options[:dir] = args[0]
+
else
- still_parsing_options = false
+ real_args << args[0]
end
- args.shift if still_parsing_options
+ args.shift
end
- Sub.new(options, args)
+ Sub.new(options, real_args)
end
- attr_reader :clean, :command, :args, :url
- attr_accessor :verbosity
+ attr_reader :clean, :command, :args, :url, :revision, :dir
def initialize(options = {:verbosity => NORMAL}, args = [])
- options = defaults.merge(options)
- @verbosity = options[:verbosity]
+ options = Sub.defaults.merge(options)
+ sys.verbosity = options[:verbosity]
@clean = options[:clean]
@command = options[:command]
- @url = options[:url] || ENV['SUB_BASE_URL'] || ENV['SVN'] || DEFAULT_BASE_URL
+ @url = options[:url]
+ @revision = options[:revision]
+ @dir = options[:dir] || '.'
@args = args
end
- def defaults
+ def self.defaults
{
:verbosity => NORMAL,
:command => :up,
}
end
def execute
- self.send(@command)
+ puts self.send(@command)
end
# commands
def up
if @args.empty?
@args = [`pwd`.chomp]
end
update_many(@args)
+ "Update complete."
end
def co
if @args.empty?
raise "Please specify a project to check out"
end
project = args.shift
dir_name = args.shift || project
- svn("co #{url}/#{project}/trunk #{dir_name}")
+ svn("co #{base}/#{project}/trunk #{dir_name}")
+ "Checkout complete."
end
+ def base
+ url || ENV['SUB_BASE_URL'] || ENV['SVN'] || DEFAULT_BASE_URL
+ end
+
+ #todo: test
+ def ext
+ external_name = args.shift
+ if external_name.nil?
+ External.externals_of(dir).join("\n")
+ else
+ old_external = get_external(dir, external_name)
+ if url || revision
+ revision_to_set = revision == 'HEAD' ? nil : revision
+ set_external(dir, external_name, url || old_external.url, revision_to_set)
+ else
+ old_external
+ end
+ end
+ end
+
+ def ignore
+ if args.empty?
+ svn("propget svn:ignore #{dir}", true).strip
+ else
+ svn("propset svn:ignore '#{args.join("\n")}' #{dir}")
+ "#{dir} now ignoring #{args.join(", ")}"
+ end
+ end
+
def help
puts """
sub - Alex's wrapper for subversion
Version: #{Sub::VERSION::STRING}
Usage:
- sub co project_name [dir_name]
- checks out [base_url]/project_name/trunk into ./project_name (or dir_name if specified)
- sub up [dir]*
+
+ sub co [--url base_url] project [dir]
+ checks out [base_url]/project/trunk into ./project (or dir if specified)
+ default base_url is ENV['SUB_BASE_URL'] or ENV['SVN']
+ or #{DEFAULT_BASE_URL}
+
+ sub up [--clean] [dir]*
fast update (default command, so 'sub dir...' or just 'sub' work too)
+ if --clean is specified, removes all unversioned files and directories
+
sub help
prints this message
+ sub ext [--dir directory] [external_name [--revision rev] [--url url]]]
+ prints the value of the named svn:external property for directory dir
+ if no dir is specified, uses '.'
+ if no external_name is specified, prints all externals in that directory
+ if --url or --revision is specified, sets the value and commits the change
+ if rev is HEAD then the revision is removed from that external
+
+ sub ignore [--dir directory] [pattern]
+ prints the value of the svn:ignore property for directory dir
+ if pattern is specified, ignores that pattern
+ if no dir is specified, uses '.'
+
Options:
--verbose, -v
lots of output
--quiet, -q
no output at all except for errors
--help, -h
prints this message
- --clean, -c
- 'up' command removes all unversioned files and directories
- --url [base_url]
- sets base repository url for 'co' command
- (default is ENV['SUB_BASE_URL'] or ENV['SVN'] or #{DEFAULT_BASE_URL})
--version
prints release version
"""
end
+
# methods
def update_many(roots)
roots.each do |root|
@@ -123,49 +181,40 @@
say "Updated %s in %.2f sec" % [root, b.real]
end
end
def update(root)
- Root.new(root, self, clean).update
+ Root.new(root, clean).update
end
- def externals(root)
- Root.new(root, self, clean).externals
+ def all_externals(root)
+ Root.new(root, clean).all_externals
end
+
+ def get_external(dir, external_name)
+ External.externals_of(dir).select do |external|
+ external.name == external_name
+ end.first
+ end
- def parse_externals(st)
- exts = []
- st.split("\n").select do |line|
- line =~ /^X/
- end.collect do |line|
- line.gsub(/^X */, '').gsub(/\/[^\/]*$/, '')
- end.uniq.collect do |parent|
- prop = `svn propget svn:externals #{parent}`
- prop.split("\n").each do |external|
- next if external.strip.empty?
- exts << External.new(parent, external, self)
- end
+ def set_external(dir, external_name, url, revision = nil)
+ if get_external(dir, external_name)
+ remove_external(dir, external_name)
end
- exts
+ new_external = External.new(dir, external_name, url, revision)
+ externals = External.externals_of(dir) << new_external
+ set_externals(dir, externals)
+ new_external
end
-
- def say(msg)
- puts msg if verbosity > QUIET
+
+ def set_externals(externals_path, externals)
+ property_lines = externals.collect { |x| x.to_s }
+ svn "propset svn:externals '#{property_lines.join("\n")}' #{externals_path}"
end
-
- def svn(cmd)
- svncmd = "svn"
- svncmd += " --quiet" if (cmd =~ /^(up|co)/ && verbosity == QUIET)
- run("#{svncmd} #{cmd}")
+
+ def remove_external(dir, name)
+ set_externals(dir, External.externals_of(dir).select { |x| x.name != name })
+ svn("ci --non-recursive -m 'removing external #{name}' #{dir}")
+ FileUtils.rm_rf("#{dir}/#{name}") # TODO: unless modified
end
- def run(cmd, return_output = false)
- say("\t#{cmd}") if verbosity == VERBOSE
- if (return_output)
- `#{cmd}`
- else
- cmd += ">/dev/null"if verbosity == QUIET
- system(cmd)
- end
- end
end
-