pvn 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. data/README.markdown +38 -0
  2. data/bin/pvn +12 -0
  3. data/bin/pvndiff +10 -0
  4. data/lib/pvn/app.rb +144 -0
  5. data/lib/pvn/base/textlines.rb +35 -0
  6. data/lib/pvn/base/util.rb +14 -0
  7. data/lib/pvn/cmddoc.rb +77 -0
  8. data/lib/pvn/config.rb +65 -0
  9. data/lib/pvn/describe.rb +40 -0
  10. data/lib/pvn/diff/diffcmd.rb +49 -0
  11. data/lib/pvn/diff/differ.rb +67 -0
  12. data/lib/pvn/diff/diffopts.rb +58 -0
  13. data/lib/pvn/doc.rb +34 -0
  14. data/lib/pvn/io/element.rb +113 -0
  15. data/lib/pvn/io/fselement.rb +22 -0
  16. data/lib/pvn/log/formatter/color_formatter.rb +29 -0
  17. data/lib/pvn/log/formatter/entries_formatter.rb +33 -0
  18. data/lib/pvn/log/formatter/entry_formatter.rb +57 -0
  19. data/lib/pvn/log/formatter/log_formatter.rb +59 -0
  20. data/lib/pvn/log/formatter/message_formatter.rb +19 -0
  21. data/lib/pvn/log/formatter/path_formatter.rb +41 -0
  22. data/lib/pvn/log/formatter/summary_formatter.rb +49 -0
  23. data/lib/pvn/log/logcmd.rb +136 -0
  24. data/lib/pvn/log/logentry.rb +116 -0
  25. data/lib/pvn/log/logfactory.rb +101 -0
  26. data/lib/pvn/log/logoptions.rb +43 -0
  27. data/lib/pvn/pct/linecount.rb +33 -0
  28. data/lib/pvn/pct/pctcmd.rb +204 -0
  29. data/lib/pvn/pct/statcmd.rb +13 -0
  30. data/lib/pvn/revision/entry.rb +94 -0
  31. data/lib/pvn/revision.rb +119 -0
  32. data/lib/pvn/subcommands/base/clargs.rb +53 -0
  33. data/lib/pvn/subcommands/base/command.rb +60 -0
  34. data/lib/pvn/subcommands/base/doc.rb +94 -0
  35. data/lib/pvn/subcommands/base/options.rb +22 -0
  36. data/lib/pvn/subcommands/log/command.rb +70 -0
  37. data/lib/pvn/subcommands/log/options.rb +43 -0
  38. data/lib/pvn/subcommands/pct/clargs.rb +33 -0
  39. data/lib/pvn/subcommands/pct/command.rb +57 -0
  40. data/lib/pvn/subcommands/revision/multiple_revisions_option.rb +43 -0
  41. data/lib/pvn/subcommands/revision/revision_option.rb +74 -0
  42. data/lib/pvn/subcommands/revision/revision_regexp_option.rb +39 -0
  43. data/lib/pvn/svn/command/svncmd.rb +39 -0
  44. data/lib/pvn/svn/environment.rb +23 -0
  45. data/lib/pvn/svn/svnelement.rb +89 -0
  46. data/lib/pvn/svn/svninfo.rb +42 -0
  47. data/lib/pvn/svn/svnroot.rb +29 -0
  48. data/lib/pvn/upp/uppcmd.rb +112 -0
  49. data/lib/pvn/wherecmd.rb +55 -0
  50. data/lib/pvn.rb +8 -0
  51. data/lib/svnx/command.rb +60 -0
  52. data/lib/svnx/entry.rb +34 -0
  53. data/lib/svnx/info/command.rb +21 -0
  54. data/lib/svnx/info/entries.rb +27 -0
  55. data/lib/svnx/info/entry.rb +34 -0
  56. data/lib/svnx/log/command.rb +93 -0
  57. data/lib/svnx/log/entries.rb +57 -0
  58. data/lib/svnx/log/entry.rb +54 -0
  59. data/lib/svnx/status/command.rb +21 -0
  60. data/lib/svnx/status/entries.rb +22 -0
  61. data/lib/svnx/status/entry.rb +33 -0
  62. data/lib/synoption/base_option.rb +149 -0
  63. data/lib/synoption/boolean_option.rb +21 -0
  64. data/lib/synoption/doc.rb +81 -0
  65. data/lib/synoption/fixnum_option.rb +13 -0
  66. data/lib/synoption/match.rb +47 -0
  67. data/lib/synoption/option.rb +10 -0
  68. data/lib/synoption/optionable.rb +66 -0
  69. data/lib/synoption/set.rb +114 -0
  70. data/lib/system/cachecmd.rb +65 -0
  71. data/lib/system/cmdexec.rb +13 -0
  72. data/lib/system/cmdline.rb +70 -0
  73. data/lib/system/command/arg.rb +12 -0
  74. data/lib/system/command/cachefile.rb +39 -0
  75. data/lib/system/command/caching.rb +36 -0
  76. data/lib/system/command/line.rb +47 -0
  77. data/lib/system/command.rb +72 -0
  78. data/test/integration/svnx/log/test.rb +43 -0
  79. data/test/unit/pvn/app_test.rb +22 -0
  80. data/test/unit/pvn/io/element/log/log_test.rb +35 -0
  81. data/test/unit/pvn/log/formatter/entry_formatter_test.rb +90 -0
  82. data/test/unit/pvn/revision/entry_test.rb +123 -0
  83. data/test/unit/pvn/subcommands/log/command_test.rb +22 -0
  84. data/test/unit/pvn/subcommands/log/options_test.rb +85 -0
  85. data/test/unit/pvn/subcommands/revision/multiple_revisions_option_test.rb +67 -0
  86. data/test/unit/pvn/subcommands/revision/revision_option_test.rb +57 -0
  87. data/test/unit/pvn/subcommands/revision/revision_regexp_option_test.rb +69 -0
  88. data/test/unit/svnx/info/entry_test.rb +52 -0
  89. data/test/unit/svnx/log/cmargs_test.rb +22 -0
  90. data/test/unit/svnx/log/entries_test.rb +73 -0
  91. data/test/unit/svnx/log/entry_test.rb +21 -0
  92. data/test/unit/svnx/status/entry_test.rb +39 -0
  93. data/test/unit/synoption/base_option_test.rb +182 -0
  94. data/test/unit/synoption/match_test.rb +61 -0
  95. data/test/unit/synoption/option_test.rb +15 -0
  96. data/test/unit/synoption/set_test.rb +37 -0
  97. data/test/unit/system/command/caching_test.rb +97 -0
  98. data/test/unit/system/command/line_test.rb +33 -0
  99. metadata +199 -0
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'svnx/entry'
5
+
6
+ module SVNx; module Status; end; end
7
+
8
+ module SVNx::Status
9
+ class Entry < SVNx::Entry
10
+
11
+ attr_reader :status
12
+ attr_reader :path
13
+
14
+ def initialize args = Hash.new
15
+ if xmllines = args[:xmllines]
16
+ doc = REXML::Document.new xmllines
17
+ stelmt = doc.elements['status']
18
+ tgt = stelmt.elements['target']
19
+
20
+ set_attr_var tgt, 'path'
21
+
22
+ if entry = tgt.elements['entry']
23
+ wcstatus = entry.elements['wc-status']
24
+ @status = wcstatus.attributes['item']
25
+ else
26
+ @status = "unchanged"
27
+ end
28
+ else
29
+ raise "must be initialized with xmllines"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'rubygems'
5
+ require 'riel'
6
+ require 'synoption/doc'
7
+ require 'synoption/match'
8
+
9
+ module PVN
10
+ class BaseOption
11
+ include Loggable
12
+
13
+ # for as_cmdline_option:
14
+ NO_CMDLINE_OPTION = Object.new
15
+
16
+ attr_reader :name
17
+ attr_reader :tag
18
+ attr_reader :description
19
+ attr_reader :default
20
+
21
+ attr_reader :negate
22
+ attr_reader :regexp
23
+
24
+ def initialize name, tag, description, default, options = Hash.new
25
+ @name = name
26
+ @tag = tag
27
+ @description = description
28
+
29
+ @value = @default = default
30
+
31
+ @matchers = Hash.new
32
+ @matchers[:exact] = OptionExactMatch.new @tag, @name
33
+
34
+ if @negate = options[:negate]
35
+ @matchers[:negative] = OptionNegativeMatch.new @negate
36
+ end
37
+
38
+ if @regexp = options[:regexp]
39
+ @matchers[:regexp] = OptionRegexpMatch.new @regexp
40
+ end
41
+
42
+ if options.include? :as_cmdline_option
43
+ if options[:as_cmdline_option].nil?
44
+ @as_cmdline_option = NO_CMDLINE_OPTION
45
+ else
46
+ @as_cmdline_option = options[:as_cmdline_option]
47
+ end
48
+ else
49
+ @as_cmdline_option = nil
50
+ end
51
+
52
+ @unsets = options[:unsets]
53
+ end
54
+
55
+ def takes_value?
56
+ true
57
+ end
58
+
59
+ def to_command_line
60
+ return nil unless value
61
+
62
+ if @as_cmdline_option
63
+ @as_cmdline_option == NO_CMDLINE_OPTION ? nil : @as_cmdline_option
64
+ else
65
+ [ tag, value ]
66
+ end
67
+ end
68
+
69
+ def to_s
70
+ [ @name, @tag ].join(", ")
71
+ end
72
+
73
+ def exact_match? arg
74
+ @matchers[:exact].match? arg
75
+ end
76
+
77
+ def negative_match? arg
78
+ @matchers[:negative] and @matchers[:negative].match? arg
79
+ end
80
+
81
+ def regexp_match? arg
82
+ @matchers[:regexp] and @matchers[:regexp].match? arg
83
+ end
84
+
85
+ def match arg
86
+ return nil unless arg
87
+
88
+ @matchers.each do |type, matcher|
89
+ if matcher.match? arg
90
+ return [ type, matcher ]
91
+ end
92
+ end
93
+
94
+ nil
95
+ end
96
+
97
+ def unset
98
+ @value = nil
99
+ end
100
+
101
+ def set_value val
102
+ @value = val
103
+ end
104
+
105
+ def value
106
+ @value
107
+ end
108
+
109
+ def to_doc io
110
+ doc = Doc.new self
111
+ doc.to_doc io
112
+ end
113
+
114
+ def next_argument args
115
+ raise "ERROR: option #{name} expecting following argument" if args.empty?
116
+ args.shift
117
+ end
118
+
119
+ def process args
120
+ if @matchers[:exact].match? args[0]
121
+ args.shift
122
+ val = takes_value? ? next_argument(args) : true
123
+ set_value val
124
+ true
125
+ elsif @matchers[:negative] && @matchers[:negative].match?(args[0])
126
+ arg = args.shift
127
+ set_value false
128
+ true
129
+ elsif @matchers[:regexp] && (md = @matchers[:regexp].match?(args[0]))
130
+ arg = args.shift
131
+ set_value md[0]
132
+ true
133
+ else
134
+ false
135
+ end
136
+ end
137
+
138
+ def post_process option_set, unprocessed
139
+ resolve_value option_set, unprocessed
140
+
141
+ if @unsets
142
+ option_set.unset @unsets
143
+ end
144
+ end
145
+
146
+ def resolve_value option_set, unprocessed
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'rubygems'
5
+ require 'riel'
6
+ require 'synoption/option'
7
+
8
+ module PVN
9
+ # a boolean option maps to a single tag, not a tag and value. For example,
10
+ # "-v" (verbose) is a boolean option, but "-r 3444" (revision) is a option
11
+ # with a value.
12
+ class BooleanOption < Option
13
+ def takes_value?
14
+ false
15
+ end
16
+
17
+ def to_command_line
18
+ super && [ tag ]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'rubygems'
5
+ require 'riel'
6
+
7
+ module PVN
8
+ # documentation for an option.
9
+ class Doc
10
+ include Loggable
11
+
12
+ def initialize option
13
+ @option = option
14
+ end
15
+
16
+ def to_doc_tag
17
+ tagline = "#{@option.tag} [--#{@option.name}]"
18
+ if @option.takes_value?
19
+ tagline << " ARG"
20
+ end
21
+ tagline
22
+ end
23
+
24
+ # returns an option regexp as a 'cleaner' string
25
+ def re_to_string re
26
+ re.source.gsub(%r{\\d\+?}, 'N').gsub(%r{[\^\?\$\\\(\)]}, '')
27
+ end
28
+
29
+ def to_doc_negate
30
+ doc = nil
31
+ @option.negate.each do |neg|
32
+ str = if neg.kind_of? Regexp
33
+ str = re_to_string neg
34
+ else
35
+ str = neg
36
+ end
37
+
38
+ if doc
39
+ doc << " [#{str}]"
40
+ else
41
+ doc = str
42
+ end
43
+ end
44
+ doc
45
+ end
46
+
47
+ # -g [--use-merge-history] : use/display additional information from merge
48
+ # 01234567890123456789012345678901234567890123456789012345678901234567890123456789
49
+ # 0 1 2 3 4 5 6
50
+
51
+ def to_doc_line lhs, rhs, sep = ""
52
+ fmt = " %-24s %1s %s"
53
+ sprintf fmt, lhs, sep, rhs
54
+ end
55
+
56
+ def to_doc io
57
+ opttag = @option.tag
58
+ optdesc = @option.description
59
+
60
+ # wrap optdesc?
61
+
62
+ @option.description.each_with_index do |descline, idx|
63
+ lhs = idx == 0 ? to_doc_tag : ""
64
+ io.puts to_doc_line lhs, descline, idx == 0 ? ":" : ""
65
+ end
66
+
67
+ if defval = @option.default
68
+ io.puts to_doc_line "", " default: #{defval}"
69
+ end
70
+
71
+ if re = @option.regexp
72
+ io.puts to_doc_line re_to_string(re), "same as above", ":"
73
+ end
74
+
75
+ if @option.negate
76
+ lhs = to_doc_negate
77
+ io.puts to_doc_line lhs, "", ""
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'synoption/option'
5
+
6
+ module PVN
7
+ # An option that has a fixnum (integer) as its value.
8
+ class FixnumOption < Option
9
+ def set_value val
10
+ super val.to_i
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'rubygems'
5
+ require 'riel'
6
+
7
+ module PVN
8
+ class OptionMatch
9
+ include Loggable
10
+
11
+ def match? arg
12
+ raise "not implemented"
13
+ end
14
+ end
15
+
16
+ class OptionExactMatch < OptionMatch
17
+ def initialize tag, name
18
+ @tag = tag
19
+ @name = name
20
+ end
21
+
22
+ def match? arg
23
+ arg == @tag || arg == '--' + @name.to_s
24
+ end
25
+ end
26
+
27
+ class OptionNegativeMatch < OptionMatch
28
+ def initialize *negopts
29
+ # in case this gets passed an array as an element:
30
+ @negopts = Array.new(negopts).flatten
31
+ end
32
+
33
+ def match? arg
34
+ arg && @negopts.select { |x| arg.index x }.size > 0
35
+ end
36
+ end
37
+
38
+ class OptionRegexpMatch < OptionMatch
39
+ def initialize regexp
40
+ @regexp = regexp
41
+ end
42
+
43
+ def match? arg
44
+ arg && @regexp.match(arg)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'synoption/base_option'
5
+
6
+ module PVN
7
+ class Option < BaseOption
8
+ include Loggable
9
+ end
10
+ end
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'rubygems'
5
+ require 'riel'
6
+ require 'synoption/set'
7
+ require 'synoption/option'
8
+ require 'pvn/cmddoc'
9
+
10
+ module PVN
11
+ module Optionable
12
+ include Loggable
13
+
14
+ def self.included base
15
+ base.extend ClassMethods
16
+ end
17
+
18
+ module ClassMethods
19
+ def has_option optname, tag, desc, args = Hash.new
20
+ RIEL::Log.debug "self: #{self}"
21
+ RIEL::Log.debug "optname: #{optname}"
22
+
23
+ self.instance_eval do
24
+ @option_set ||= OptionSet.new
25
+ opt = Option.new optname, tag, desc, args
26
+ @option_set.options << opt
27
+
28
+ RIEL::Log.debug "self: #{self}"
29
+ RIEL::Log.debug "opt: #{opt.inspect}"
30
+ RIEL::Log.debug "@option_set: #{@option_set.inspect}"
31
+
32
+ @doc.options << opt
33
+ end
34
+ end
35
+
36
+ def find_option optname
37
+ self.instance_eval do
38
+ @option_set.find_by_name optname
39
+ end
40
+ end
41
+
42
+ def doc
43
+ @doc ||= CommandDoc.new
44
+ yield @doc if block_given?
45
+ @doc
46
+ end
47
+
48
+ def options
49
+ self.instance_eval do
50
+ @option_set ||= OptionSet.new
51
+ RIEL::Log.debug "@option_set: #{@option_set}"
52
+ yield @option_set if block_given?
53
+ @option_set
54
+ end
55
+ end
56
+
57
+ def to_doc io = $stdout
58
+ self.instance_eval { @doc.to_doc io }
59
+ end
60
+
61
+ def next_argument_as_integer ca, cmdargs
62
+ cmdargs.shift.to_i
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'rubygems'
5
+ require 'riel'
6
+ require 'synoption/option'
7
+
8
+ module PVN
9
+ class OptionSet
10
+ include Loggable
11
+
12
+ # maps from the option set class to the valid options for that class.
13
+ @@options_for_class = Hash.new { |h, k| h[k] = Array.new }
14
+
15
+ attr_reader :unprocessed
16
+
17
+ class << self
18
+ def has_option name, optcls, optargs = Hash.new
19
+ attr_reader name
20
+
21
+ @@options_for_class[self] << { :name => name, :class => optcls, :args => optargs }
22
+
23
+ define_method name do
24
+ instance_eval do
25
+ meth = name
26
+ opt = instance_variable_get '@' + name.to_s
27
+ opt.value
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ attr_reader :options
34
+ attr_reader :arguments
35
+
36
+ def initialize options = Array.new
37
+ @options = options
38
+ @arguments = Array.new
39
+
40
+ opts = @@options_for_class[self.class]
41
+
42
+ opts.each do |option|
43
+ name = option[:name]
44
+ cls = option[:class]
45
+ args = option[:args]
46
+ opt = cls.new(*args)
47
+ add opt
48
+ instance_variable_set '@' + name.to_s, opt
49
+ end
50
+ end
51
+
52
+ def inspect
53
+ @options.collect { |opt| opt.inspect }.join("\n")
54
+ end
55
+
56
+ def find_by_name name
57
+ @options.find { |opt| opt.name == name }
58
+ end
59
+
60
+ def has_option? name
61
+ find_by_name name
62
+ end
63
+
64
+ def to_command_line
65
+ cmdline = Array.new
66
+ @options.each do |opt|
67
+ if cl = opt.to_command_line
68
+ cmdline.concat cl
69
+ end
70
+ end
71
+ cmdline
72
+ end
73
+
74
+ def unset key
75
+ opt = find_by_name key
76
+ opt && opt.unset
77
+ end
78
+
79
+ def process args
80
+ options_processed = Array.new
81
+
82
+ @unprocessed = args
83
+
84
+ while !@unprocessed.empty?
85
+ processed = false
86
+ options.each do |opt|
87
+ if opt.process @unprocessed
88
+ processed = true
89
+ options_processed << opt
90
+ end
91
+ end
92
+
93
+ break unless processed
94
+ end
95
+
96
+ options_processed.each do |opt|
97
+ opt.post_process self, @unprocessed
98
+ end
99
+ end
100
+
101
+ def << option
102
+ @options << option
103
+ end
104
+
105
+ def add option
106
+ @options << option
107
+ option
108
+ end
109
+
110
+ def as_command_line
111
+ to_command_line + arguments
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ require 'system/command'
5
+
6
+ module PVN
7
+ class CachableCommand < Command
8
+ TMP_DIR = ENV['PVN_TMP_DIR'] || '/tmp/pvncache'
9
+ CACHE_DIR = Pathname.new TMP_DIR
10
+
11
+ attr_accessor :lines
12
+
13
+ def initialize args = Hash.new
14
+ debug "args: #{args.inspect}"
15
+
16
+ @use_cache = args[:use_cache].nil? ? true : args[:use_cache]
17
+ info "@use_cache: #{@use_cache}".blue
18
+
19
+ super
20
+ end
21
+
22
+ def sysexec cmd
23
+ info "cmd: #{cmd}".on_red
24
+ if use_cache?
25
+ info "cmd: #{cmd}".on_green
26
+ run_cached_command cmd
27
+ else
28
+ @output = ::IO::popen(cmd).readlines
29
+ end
30
+ end
31
+
32
+ def run args
33
+ if use_cache?
34
+ run_cached_command args
35
+ else
36
+ super
37
+ end
38
+ end
39
+
40
+ def use_cache?
41
+ @use_cache
42
+ end
43
+
44
+ def get_cache_file cmd
45
+ pwd = Pathname.pwd.to_s.sub(%r{^/}, '')
46
+ CACHE_DIR + pwd + cmd.gsub(' ', '')
47
+ end
48
+
49
+ def run_cached_command cmd
50
+ stack "cmd: #{cmd}".cyan
51
+ cfile = get_cache_file cmd
52
+ if cfile.exist?
53
+ debug "reading from cache file: #{cfile}".cyan
54
+ @output = cfile.readlines
55
+ else
56
+ @output = ::IO::popen(cmd).readlines
57
+ cfile.parent.mkpath
58
+ stack "saving output to cache file: #{cfile}".cyan
59
+ File.put_via_temp_file cfile do
60
+ output
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ module PVN
5
+ class CommandExecutor
6
+ def initialize
7
+ end
8
+
9
+ def run cmd
10
+ IO.popen(cmd).readlines
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ module PVN
5
+ class CommandLine
6
+ include Loggable
7
+
8
+ attr_reader :output
9
+ attr_accessor :use_cache
10
+
11
+ def initialize use_cache, args = Array.new
12
+ @args = args.dup
13
+ @use_cache = use_cache
14
+ end
15
+
16
+ def use_cache?
17
+ @use_cache
18
+ end
19
+
20
+ def cache_dir
21
+ nil
22
+ end
23
+
24
+ def << arg
25
+ @args << arg
26
+ end
27
+
28
+ def execute
29
+ if use_cache?
30
+ run_cached_command
31
+ else
32
+ @output = ::IO.popen(to_command).readlines
33
+ end
34
+ end
35
+
36
+ def to_command
37
+ @args.join ' '
38
+ end
39
+
40
+ def run args
41
+ if use_cache?
42
+ run_cached_command
43
+ else
44
+ super
45
+ end
46
+ end
47
+
48
+ def get_cache_file
49
+ pwd = Pathname.pwd.split_path.join('')
50
+ info "pwd: #{pwd}"
51
+ Pathname.new(cache_dir) + pwd + @args.join('-')
52
+ end
53
+
54
+ def run_cached_command
55
+ stack "@args: #{@args}".cyan
56
+ cachefile = get_cache_file
57
+ if cachefile.exist?
58
+ debug "reading from cache file: #{cachefile}".cyan
59
+ @output = cachefile.readlines
60
+ else
61
+ @output = IO.popen(to_command).readlines
62
+ cachefile.parent.mkpath
63
+ debug "saving output to cache file: #{cachefile}".on_cyan
64
+ File.put_via_temp_file cachefile do
65
+ @output
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/ruby -w
2
+ # -*- ruby -*-
3
+
4
+ module System
5
+ class Argument < String
6
+ # just a string, but quotes itself
7
+
8
+ def to_s
9
+ '"' + super + '"'
10
+ end
11
+ end
12
+ end