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 -