| 1 | #!/usr/bin/env ruby |
|---|
| 2 | # vim:ft=ruby: |
|---|
| 3 | |
|---|
| 4 | require "optparse" |
|---|
| 5 | require "pathname" |
|---|
| 6 | require "userscripts_org" |
|---|
| 7 | |
|---|
| 8 | class UserjsCommand |
|---|
| 9 | VERSION = UserscriptsOrg::VERSION |
|---|
| 10 | NAME = "user.js" |
|---|
| 11 | |
|---|
| 12 | def self.run(argv) |
|---|
| 13 | new(argv.dup).run |
|---|
| 14 | end |
|---|
| 15 | |
|---|
| 16 | def initialize(argv) |
|---|
| 17 | @argv = argv |
|---|
| 18 | |
|---|
| 19 | @subparsers = { |
|---|
| 20 | "help" => OptionParser.new { |opts| |
|---|
| 21 | opts.banner = <<-EOB.gsub(/^\t+/, "") |
|---|
| 22 | Usage: #{NAME} help <subcommand> |
|---|
| 23 | |
|---|
| 24 | Show help of subcommand. |
|---|
| 25 | EOB |
|---|
| 26 | }, |
|---|
| 27 | |
|---|
| 28 | "list" => OptionParser.new { |opts| |
|---|
| 29 | opts.banner = <<-EOB.gsub(/^\t+/, "") |
|---|
| 30 | Usage: #{NAME} list |
|---|
| 31 | |
|---|
| 32 | List your scripts. |
|---|
| 33 | EOB |
|---|
| 34 | }, |
|---|
| 35 | |
|---|
| 36 | "update" => OptionParser.new { |opts| |
|---|
| 37 | opts.banner = <<-EOB.gsub(/^\t+/, "") |
|---|
| 38 | Usage: #{NAME} update <filename> |
|---|
| 39 | |
|---|
| 40 | Update <filename> script. |
|---|
| 41 | EOB |
|---|
| 42 | }, |
|---|
| 43 | |
|---|
| 44 | "create" => OptionParser.new { |opts| |
|---|
| 45 | opts.banner = <<-EOB.gsub(/^\t+/, "") |
|---|
| 46 | Usage: #{NAME} create <filename> |
|---|
| 47 | |
|---|
| 48 | Create entry on userscripts.org with <filename> script. |
|---|
| 49 | EOB |
|---|
| 50 | }, |
|---|
| 51 | |
|---|
| 52 | "install" => OptionParser.new { |opts| |
|---|
| 53 | opts.banner = <<-EOB.gsub(/^\t+/, "") |
|---|
| 54 | Usage: #{NAME} install [opts] <filename> |
|---|
| 55 | |
|---|
| 56 | Install <filename> script. |
|---|
| 57 | EOB |
|---|
| 58 | |
|---|
| 59 | opts.separator "" |
|---|
| 60 | |
|---|
| 61 | opts.separator "Options:" |
|---|
| 62 | opts.on('-l', '--symlink', "Replace installed file with symlink.") do |
|---|
| 63 | @symlink = true |
|---|
| 64 | end |
|---|
| 65 | }, |
|---|
| 66 | |
|---|
| 67 | } |
|---|
| 68 | |
|---|
| 69 | @parser = OptionParser.new do |parser| |
|---|
| 70 | parser.banner = <<-EOB.gsub(/^\t+/, "") |
|---|
| 71 | Usage: #{NAME} <subcommand> <args> |
|---|
| 72 | |
|---|
| 73 | EOB |
|---|
| 74 | |
|---|
| 75 | parser.separator "" |
|---|
| 76 | |
|---|
| 77 | parser.separator "Subcommands:" |
|---|
| 78 | @subparsers.keys.sort.each do |k| |
|---|
| 79 | parser.separator "#{parser.summary_indent} #{k}" |
|---|
| 80 | end |
|---|
| 81 | |
|---|
| 82 | parser.separator "" |
|---|
| 83 | |
|---|
| 84 | parser.separator "Options:" |
|---|
| 85 | parser.on('--version', "Show version string `#{VERSION}'") do |
|---|
| 86 | puts VERSION |
|---|
| 87 | exit |
|---|
| 88 | end |
|---|
| 89 | end |
|---|
| 90 | end |
|---|
| 91 | |
|---|
| 92 | def run |
|---|
| 93 | @parser.order!(@argv) |
|---|
| 94 | if @argv.empty? |
|---|
| 95 | puts @parser.help |
|---|
| 96 | exit |
|---|
| 97 | else |
|---|
| 98 | @subcommand = @argv.shift |
|---|
| 99 | method_name = "cmd_#{@subcommand}" |
|---|
| 100 | if self.respond_to?(method_name) |
|---|
| 101 | @subparsers[@subcommand].parse!(@argv) |
|---|
| 102 | self.send(method_name) |
|---|
| 103 | else |
|---|
| 104 | puts "Not implemented subcommand: `#{@subcommand}'." |
|---|
| 105 | puts |
|---|
| 106 | puts @parser.help |
|---|
| 107 | end |
|---|
| 108 | end |
|---|
| 109 | end |
|---|
| 110 | |
|---|
| 111 | def cmd_help |
|---|
| 112 | subcommand, = @argv |
|---|
| 113 | if subcommand |
|---|
| 114 | if @subparsers.key? subcommand |
|---|
| 115 | puts @subparsers[subcommand].help |
|---|
| 116 | else |
|---|
| 117 | puts "No such subcommand `#{subcommand}'" |
|---|
| 118 | puts @parser.help |
|---|
| 119 | end |
|---|
| 120 | else |
|---|
| 121 | puts @parser.help |
|---|
| 122 | end |
|---|
| 123 | end |
|---|
| 124 | |
|---|
| 125 | def cmd_list |
|---|
| 126 | usorg = login() |
|---|
| 127 | usorg.list.each do |s| |
|---|
| 128 | puts "%8d: %s" % [s.uid, s.name] |
|---|
| 129 | end |
|---|
| 130 | end |
|---|
| 131 | |
|---|
| 132 | def cmd_update |
|---|
| 133 | abort @subparsers[@subcommand].help if @argv.empty? |
|---|
| 134 | content = File.read(@argv.first) |
|---|
| 135 | name = content[/@name\s+(.+)\s*/, 1] |
|---|
| 136 | |
|---|
| 137 | usorg = login() |
|---|
| 138 | warn "Update..." |
|---|
| 139 | usorg.update(name, content) |
|---|
| 140 | end |
|---|
| 141 | |
|---|
| 142 | def cmd_create |
|---|
| 143 | abort @subparsers[@subcommand].help if @argv.empty? |
|---|
| 144 | content = File.read(@argv.first) |
|---|
| 145 | |
|---|
| 146 | usorg = login() |
|---|
| 147 | warn "Update..." |
|---|
| 148 | usorg.create(content) |
|---|
| 149 | end |
|---|
| 150 | |
|---|
| 151 | def cmd_install |
|---|
| 152 | abort @subparsers[@subcommand].help if @argv.empty? |
|---|
| 153 | file = Pathname.new(@argv.first).realpath |
|---|
| 154 | prev = scan |
|---|
| 155 | install_userjs(file) |
|---|
| 156 | return unless @symlink |
|---|
| 157 | installed = catch(:break) { |
|---|
| 158 | loop do |
|---|
| 159 | scan.each do |f,time| |
|---|
| 160 | if prev.key?(f) |
|---|
| 161 | throw :break, f unless prev[f] == time |
|---|
| 162 | else |
|---|
| 163 | throw :break, f |
|---|
| 164 | end |
|---|
| 165 | end |
|---|
| 166 | sleep 1 |
|---|
| 167 | end |
|---|
| 168 | } |
|---|
| 169 | puts "#{file} was installed as #{installed}." |
|---|
| 170 | puts "#{installed} will be replaced with symlink to #{file}." |
|---|
| 171 | |
|---|
| 172 | FileUtils.symlink(file, installed, :force => true) |
|---|
| 173 | puts "done" |
|---|
| 174 | end |
|---|
| 175 | |
|---|
| 176 | |
|---|
| 177 | private |
|---|
| 178 | def login |
|---|
| 179 | warn "Logging in..." |
|---|
| 180 | UserscriptsOrg.new(Pit.get("userscripts.org", :require => { |
|---|
| 181 | "username" => "username", |
|---|
| 182 | "password" => "password" |
|---|
| 183 | })).login |
|---|
| 184 | end |
|---|
| 185 | |
|---|
| 186 | def profile_dir |
|---|
| 187 | dir = nil |
|---|
| 188 | case RUBY_PLATFORM |
|---|
| 189 | when /darwin/ |
|---|
| 190 | dir = "~/Library/Application Support/Firefox/Profiles" |
|---|
| 191 | when /win/ |
|---|
| 192 | dir = "~/Application Data/Mozilla/Firefox/Profiles" |
|---|
| 193 | when |
|---|
| 194 | dir = "~/.mozilla/firefox" |
|---|
| 195 | end |
|---|
| 196 | Pathname.new(dir).expand_path |
|---|
| 197 | end |
|---|
| 198 | |
|---|
| 199 | def scan |
|---|
| 200 | Pathname.glob(profile_dir + "*/gm_scripts/**/*.user.js").inject({}) {|r,i| |
|---|
| 201 | r[i] = i.mtime |
|---|
| 202 | r |
|---|
| 203 | } |
|---|
| 204 | end |
|---|
| 205 | |
|---|
| 206 | def install_userjs(path) |
|---|
| 207 | case RUBY_PLATFORM |
|---|
| 208 | when /darwin/ |
|---|
| 209 | system("open", "-a", "Firefox", path.to_s) |
|---|
| 210 | when /win/ |
|---|
| 211 | abort "Not supported OS #{RUBY_PLATFORM}" |
|---|
| 212 | when |
|---|
| 213 | system("firefox", path.to_s) |
|---|
| 214 | end |
|---|
| 215 | puts "Complete the install on Firefox" |
|---|
| 216 | end |
|---|
| 217 | end |
|---|
| 218 | |
|---|
| 219 | |
|---|
| 220 | UserjsCommand.run(ARGV) |
|---|
| 221 | |
|---|