rosette-client 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +14 -0
- data/History.txt +3 -0
- data/README.md +4 -0
- data/Rakefile +18 -0
- data/bin/git-rosette +17 -0
- data/lib/rosette/client/api.rb +128 -0
- data/lib/rosette/client/cli.rb +42 -0
- data/lib/rosette/client/commands/commit_command.rb +42 -0
- data/lib/rosette/client/commands/diff_command.rb +110 -0
- data/lib/rosette/client/commands/repo_snapshot_command.rb +38 -0
- data/lib/rosette/client/commands/show_command.rb +40 -0
- data/lib/rosette/client/commands/snapshot_command.rb +41 -0
- data/lib/rosette/client/commands/status_command.rb +96 -0
- data/lib/rosette/client/commands.rb +68 -0
- data/lib/rosette/client/repo.rb +32 -0
- data/lib/rosette/client/response.rb +38 -0
- data/lib/rosette/client/terminal.rb +33 -0
- data/lib/rosette/client/version.rb +7 -0
- data/lib/rosette/client.rb +13 -0
- data/rosette-client.gemspec +23 -0
- data/spec/api_spec.rb +96 -0
- data/spec/cli_spec.rb +33 -0
- data/spec/commands/commit_command_spec.rb +69 -0
- data/spec/commands/diff_command_spec.rb +151 -0
- data/spec/commands/repo_snapshot_command_spec.rb +71 -0
- data/spec/commands/show_command_spec.rb +72 -0
- data/spec/commands/snapshot_command_spec.rb +72 -0
- data/spec/commands/status_command_spec.rb +77 -0
- data/spec/helpers/fake_terminal.rb +30 -0
- data/spec/repo_spec.rb +31 -0
- data/spec/response_spec.rb +51 -0
- data/spec/spec_helper.rb +49 -0
- data/spec/terminal_spec.rb +22 -0
- metadata +108 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ca6f02478fbb347742958dd575df86db72b742c6
|
4
|
+
data.tar.gz: c43753c2cedbfa451b2c69215df10c82a49d8979
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 28b9c44f0d32376b59a3f98e653e59050be2339293de23c8bb6315f4f90b5dac263a3e6e32aedc915a1c916446dc49bd64fc7ac7f5c21560cb052c4e19bf5012
|
7
|
+
data.tar.gz: 5a85c962749d9ff7ba04082641ecac2d055822357491b0fab6e904dac377ee0eaee840d13fb09ecbea8b610e212ec3afd4c824f6ce1d3e64c24b6750f2a99829
|
data/Gemfile
ADDED
data/History.txt
ADDED
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
4
|
+
|
5
|
+
require 'bundler'
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
require 'rubygems/package_task'
|
8
|
+
|
9
|
+
require './lib/rosette/client'
|
10
|
+
|
11
|
+
Bundler::GemHelper.install_tasks
|
12
|
+
|
13
|
+
task :default => :spec
|
14
|
+
|
15
|
+
desc 'Run specs'
|
16
|
+
RSpec::Core::RakeTask.new do |t|
|
17
|
+
t.pattern = './spec/**/*_spec.rb'
|
18
|
+
end
|
data/bin/git-rosette
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rosette/client'
|
4
|
+
|
5
|
+
config_file = File.join(Dir.home, '.rosette/config.yml')
|
6
|
+
|
7
|
+
api = Rosette::Client::Api.new(
|
8
|
+
if File.exist?(config_file)
|
9
|
+
YAML.load_file(config_file)
|
10
|
+
else
|
11
|
+
{}
|
12
|
+
end
|
13
|
+
)
|
14
|
+
|
15
|
+
terminal = Rosette::Client::Terminal.new
|
16
|
+
repo = Rosette::Client::Repo.new(Dir.getwd)
|
17
|
+
Rosette::Client::Cli.new(terminal, api, repo).start(ARGV)
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'cgi'
|
4
|
+
require 'net/http'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
module Rosette
|
8
|
+
module Client
|
9
|
+
|
10
|
+
class ApiError < StandardError; end
|
11
|
+
|
12
|
+
class Api
|
13
|
+
DEFAULT_HOST = 'localhost'
|
14
|
+
DEFAULT_PORT = 8080
|
15
|
+
DEFAULT_VERSION = 'v1'
|
16
|
+
|
17
|
+
attr_reader :host, :port, :version
|
18
|
+
|
19
|
+
def initialize(options = {})
|
20
|
+
@host = options.fetch(:host, DEFAULT_HOST)
|
21
|
+
@port = options.fetch(:port, DEFAULT_PORT)
|
22
|
+
@version = options.fetch(:version, DEFAULT_VERSION)
|
23
|
+
end
|
24
|
+
|
25
|
+
def diff(params)
|
26
|
+
wrap(make_request(:get, 'git/diff.json', params))
|
27
|
+
end
|
28
|
+
|
29
|
+
def show(params)
|
30
|
+
wrap(make_request(:get, 'git/show.json', params))
|
31
|
+
end
|
32
|
+
|
33
|
+
def status(params)
|
34
|
+
wrap(make_request(:get, 'git/status.json', params))
|
35
|
+
end
|
36
|
+
|
37
|
+
def commit(params)
|
38
|
+
wrap(make_request(:get, 'git/commit.json', params))
|
39
|
+
end
|
40
|
+
|
41
|
+
def snapshot(params)
|
42
|
+
wrap(make_request(:get, 'git/snapshot.json', params))
|
43
|
+
end
|
44
|
+
|
45
|
+
def repo_snapshot(params)
|
46
|
+
wrap(make_request(:get, 'git/repo_snapshot.json', params))
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_or_update_translation(params)
|
50
|
+
wrap(make_request(:post, 'translations/add_or_update.json', params))
|
51
|
+
end
|
52
|
+
|
53
|
+
def export(params)
|
54
|
+
wrap(make_request(:get, 'translations/export.json', params))
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def wrap(api_response)
|
60
|
+
Response.from_api_response(api_response)
|
61
|
+
end
|
62
|
+
|
63
|
+
def base_url
|
64
|
+
"http://#{host}:#{port}/#{version}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def make_request(verb, path, params)
|
68
|
+
parse_response(
|
69
|
+
case verb
|
70
|
+
when :post
|
71
|
+
url = make_post_url(path, params)
|
72
|
+
post(url, params)
|
73
|
+
when :get
|
74
|
+
url = make_get_url(path, params)
|
75
|
+
get(url)
|
76
|
+
else
|
77
|
+
raise ArgumentError, "unsupported HTTP verb #{verb}."
|
78
|
+
end
|
79
|
+
)
|
80
|
+
rescue => e
|
81
|
+
raise ApiError, e.message
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_response(response)
|
85
|
+
JSON.parse(response)
|
86
|
+
end
|
87
|
+
|
88
|
+
def make_param_string(params)
|
89
|
+
(params.map do |key, val|
|
90
|
+
"#{CGI.escape(key.to_s)}=#{CGI.escape(val.to_s)}"
|
91
|
+
end).join("&")
|
92
|
+
end
|
93
|
+
|
94
|
+
def make_get_url(path, params)
|
95
|
+
File.join(base_url, path, "?#{make_param_string(params)}")
|
96
|
+
end
|
97
|
+
|
98
|
+
def make_post_url(path, params)
|
99
|
+
File.join(base_url, path)
|
100
|
+
end
|
101
|
+
|
102
|
+
def post(url, params)
|
103
|
+
uri = parse_uri(url)
|
104
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
105
|
+
request = Net::HTTP::Post.new(uri.path)
|
106
|
+
request.body = make_param_string(params)
|
107
|
+
resp = http.request(request)
|
108
|
+
resp.body
|
109
|
+
end
|
110
|
+
|
111
|
+
def get(url)
|
112
|
+
resp = Net::HTTP.get_response(parse_uri(url))
|
113
|
+
resp.body
|
114
|
+
end
|
115
|
+
|
116
|
+
# hack to handle bug in URI.parse, which doesn't allow subdomains to contain underscores
|
117
|
+
def parse_uri(url = nil)
|
118
|
+
URI.parse(url)
|
119
|
+
rescue URI::InvalidURIError
|
120
|
+
host = url.match(".+\:\/\/([^\/]+)")[1]
|
121
|
+
uri = URI.parse(url.sub(host, 'dummy-host'))
|
122
|
+
uri.instance_variable_set('@host', host)
|
123
|
+
uri
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Rosette
|
6
|
+
module Client
|
7
|
+
|
8
|
+
class Cli
|
9
|
+
attr_reader :api, :terminal, :repo
|
10
|
+
|
11
|
+
def initialize(terminal, api, repo)
|
12
|
+
@api = api
|
13
|
+
@terminal = terminal
|
14
|
+
@repo = repo
|
15
|
+
end
|
16
|
+
|
17
|
+
def start(argv)
|
18
|
+
if command_const = find_command_const(argv.first)
|
19
|
+
command_const.new(api, terminal, repo, argv[1..-1]).execute
|
20
|
+
else
|
21
|
+
terminal.say("Command '#{argv.first}' not recognized.")
|
22
|
+
end
|
23
|
+
rescue Rosette::Client::ApiError => e
|
24
|
+
terminal.say("An api error occurred: #{e.message}")
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def find_command_const(name)
|
30
|
+
const = const_name(name)
|
31
|
+
if Rosette::Client::Commands.const_defined?(const)
|
32
|
+
Rosette::Client::Commands.const_get(const)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def const_name(name)
|
37
|
+
name.downcase.gsub(/(\A\w|_\w)/) { $1.sub('_', '').upcase } + 'Command'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# git rs commit <ref>
|
4
|
+
|
5
|
+
module Rosette
|
6
|
+
module Client
|
7
|
+
module Commands
|
8
|
+
|
9
|
+
CommitCommandArgs = Struct.new(:ref) do
|
10
|
+
def self.from_argv(argv, repo)
|
11
|
+
new(repo.rev_parse(argv[0] || repo.get_head))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class CommitCommand < Command
|
16
|
+
attr_reader :args
|
17
|
+
|
18
|
+
def initialize(api, terminal, repo, argv)
|
19
|
+
super(api, terminal, repo)
|
20
|
+
@args = CommitCommandArgs.from_argv(argv, repo)
|
21
|
+
end
|
22
|
+
|
23
|
+
def execute
|
24
|
+
terminal.say("Committing phrases for '#{args.ref}'...")
|
25
|
+
|
26
|
+
response = api.commit(
|
27
|
+
repo_name: derive_repo_name,
|
28
|
+
ref: args.ref
|
29
|
+
)
|
30
|
+
|
31
|
+
handle_error(response) do
|
32
|
+
terminal.say("Added: #{response.added || 0}")
|
33
|
+
terminal.say("Removed: #{response.removed || 0}")
|
34
|
+
terminal.say("Modified: #{response.modified || 0}")
|
35
|
+
terminal.say('done.')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# git rs diff <ref1> [<ref2> | <path>] [-- <path1> <path2> ...]
|
4
|
+
|
5
|
+
# git rs diff
|
6
|
+
# git rs diff master .
|
7
|
+
# git rs diff master branch
|
8
|
+
# git rs diff master branch .
|
9
|
+
# git rs diff master branch -- path/to/files
|
10
|
+
|
11
|
+
module Rosette
|
12
|
+
module Client
|
13
|
+
module Commands
|
14
|
+
|
15
|
+
DiffCommandArgs = Struct.new(:diff_point_ref, :head_ref, :paths) do
|
16
|
+
# should probably use a parser for these args, since they're pretty complicated
|
17
|
+
# currently no support for options like --name-only, etc
|
18
|
+
def self.from_argv(argv, repo)
|
19
|
+
diff_point_ref = repo.rev_parse(argv[0] || 'refs/heads/master')
|
20
|
+
paths = []
|
21
|
+
|
22
|
+
if argv[1]
|
23
|
+
if File.exist?(argv[1])
|
24
|
+
paths << argv[1]
|
25
|
+
else
|
26
|
+
head_ref = argv[1] unless argv[1] == '--'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
head_ref ||= repo.rev_parse(repo.get_head)
|
31
|
+
|
32
|
+
(2..argv.size).each do |i|
|
33
|
+
next if argv[i] == '--'
|
34
|
+
if argv[i] && File.exist?(argv[i])
|
35
|
+
paths << argv[i]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
new(diff_point_ref, head_ref, paths)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class DiffCommand < Command
|
44
|
+
attr_reader :args
|
45
|
+
|
46
|
+
def initialize(api, terminal, repo, argv)
|
47
|
+
super(api, terminal, repo)
|
48
|
+
@args = DiffCommandArgs.from_argv(argv, repo)
|
49
|
+
end
|
50
|
+
|
51
|
+
def execute
|
52
|
+
response = api.diff(
|
53
|
+
repo_name: derive_repo_name,
|
54
|
+
head_ref: args.head_ref,
|
55
|
+
diff_point_ref: args.diff_point_ref,
|
56
|
+
paths: args.paths.join(' ')
|
57
|
+
)
|
58
|
+
|
59
|
+
handle_error(response) do |response|
|
60
|
+
print_diff(response.attributes)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def add_str_for(change)
|
67
|
+
str = "#{change['key']}"
|
68
|
+
meta_key = change['meta_key']
|
69
|
+
|
70
|
+
unless meta_key.empty?
|
71
|
+
str += " (#{meta_key})"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def remove_str_for(change)
|
76
|
+
str = "#{change.fetch('old_key', change['key'])}"
|
77
|
+
meta_key = change['meta_key']
|
78
|
+
|
79
|
+
unless meta_key.empty?
|
80
|
+
str += " (#{meta_key})"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def print_diff(diff)
|
85
|
+
group_diff_by_file(diff).each_pair do |path, states|
|
86
|
+
terminal.say("diff --rosette a/#{path} b/#{path}", :white)
|
87
|
+
|
88
|
+
states.each do |state, changes|
|
89
|
+
changes.each do |change|
|
90
|
+
add_str = add_str_for(change)
|
91
|
+
remove_str = remove_str_for(change)
|
92
|
+
|
93
|
+
case state
|
94
|
+
when 'modified'
|
95
|
+
terminal.say("- #{remove_str}", :red)
|
96
|
+
terminal.say("+ #{add_str}", :green)
|
97
|
+
when 'removed'
|
98
|
+
terminal.say("- #{remove_str}", :red)
|
99
|
+
when 'added'
|
100
|
+
terminal.say("+ #{add_str}", :green)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# git rs snapshot <ref>
|
4
|
+
|
5
|
+
module Rosette
|
6
|
+
module Client
|
7
|
+
module Commands
|
8
|
+
|
9
|
+
RepoSnapshotCommandArgs = Struct.new(:ref) do
|
10
|
+
def self.from_argv(argv, repo)
|
11
|
+
new(repo.rev_parse(argv[0] || repo.get_head))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# a show is really just a diff against your parent (so the inheritance makes sense)
|
16
|
+
class RepoSnapshotCommand < Command
|
17
|
+
attr_reader :args
|
18
|
+
|
19
|
+
def initialize(api, terminal, repo, argv)
|
20
|
+
super(api, terminal, repo)
|
21
|
+
@args = RepoSnapshotCommandArgs.from_argv(argv, repo)
|
22
|
+
end
|
23
|
+
|
24
|
+
def execute
|
25
|
+
response = api.repo_snapshot(
|
26
|
+
repo_name: derive_repo_name,
|
27
|
+
ref: args.ref
|
28
|
+
)
|
29
|
+
|
30
|
+
handle_error(response) do |response|
|
31
|
+
print_hash(response.attributes)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# git rs show <ref>
|
4
|
+
|
5
|
+
module Rosette
|
6
|
+
module Client
|
7
|
+
module Commands
|
8
|
+
|
9
|
+
ShowCommandArgs = Struct.new(:ref) do
|
10
|
+
def self.from_argv(argv, repo)
|
11
|
+
new(repo.rev_parse(argv[0] || repo.get_head))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# a show is really just a diff against your parent (so the inheritance makes sense)
|
16
|
+
class ShowCommand < DiffCommand
|
17
|
+
attr_reader :args
|
18
|
+
|
19
|
+
def initialize(api, terminal, repo, argv)
|
20
|
+
@api = api
|
21
|
+
@terminal = terminal
|
22
|
+
@repo = repo
|
23
|
+
@args = ShowCommandArgs.from_argv(argv, repo)
|
24
|
+
end
|
25
|
+
|
26
|
+
def execute
|
27
|
+
response = api.show(
|
28
|
+
repo_name: derive_repo_name,
|
29
|
+
ref: args.ref
|
30
|
+
)
|
31
|
+
|
32
|
+
handle_error(response) do |response|
|
33
|
+
print_diff(response.attributes)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# git rs snapshot <ref>
|
4
|
+
|
5
|
+
module Rosette
|
6
|
+
module Client
|
7
|
+
module Commands
|
8
|
+
|
9
|
+
SnapshotCommandArgs = Struct.new(:ref) do
|
10
|
+
def self.from_argv(argv, repo)
|
11
|
+
new(repo.rev_parse(argv[0] || repo.get_head))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# a show is really just a diff against your parent (so the inheritance makes sense)
|
16
|
+
class SnapshotCommand < Command
|
17
|
+
attr_reader :args
|
18
|
+
|
19
|
+
def initialize(api, terminal, repo, argv)
|
20
|
+
super(api, terminal, repo)
|
21
|
+
@args = SnapshotCommandArgs.from_argv(argv, repo)
|
22
|
+
end
|
23
|
+
|
24
|
+
def execute
|
25
|
+
response = api.snapshot(
|
26
|
+
repo_name: derive_repo_name,
|
27
|
+
ref: args.ref
|
28
|
+
)
|
29
|
+
|
30
|
+
handle_error(response) do |response|
|
31
|
+
response.attributes.each do |item|
|
32
|
+
print_hash(item)
|
33
|
+
terminal.say('')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
# git rs status [ref]
|
4
|
+
|
5
|
+
module Rosette
|
6
|
+
module Client
|
7
|
+
module Commands
|
8
|
+
|
9
|
+
StatusCommandArgs = Struct.new(:ref) do
|
10
|
+
def self.from_argv(argv, repo)
|
11
|
+
new(repo.rev_parse(argv[0] || repo.get_head))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# a show is really just a diff against your parent (so the inheritance makes sense)
|
16
|
+
class StatusCommand < Command
|
17
|
+
attr_reader :args
|
18
|
+
|
19
|
+
def initialize(api, terminal, repo, argv)
|
20
|
+
@api = api
|
21
|
+
@terminal = terminal
|
22
|
+
@repo = repo
|
23
|
+
@args = StatusCommandArgs.from_argv(argv, repo)
|
24
|
+
end
|
25
|
+
|
26
|
+
def execute
|
27
|
+
response = api.status(
|
28
|
+
repo_name: derive_repo_name,
|
29
|
+
ref: args.ref
|
30
|
+
)
|
31
|
+
|
32
|
+
handle_error(response) do |response|
|
33
|
+
if response.locales && response.phrase_count
|
34
|
+
terminal.say(
|
35
|
+
build_locale_table(response.locales, response.phrase_count)
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
HEADER = ['Locale', 'Phrases', 'Translations', 'Percent']
|
44
|
+
|
45
|
+
def build_locale_table(locales, phrase_count)
|
46
|
+
rows = build_locale_rows(locales, phrase_count)
|
47
|
+
column_widths = find_column_widths(rows)
|
48
|
+
rows = pad_rows(rows, column_widths)
|
49
|
+
add_markup(rows)
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_markup(rows)
|
53
|
+
rows = rows.map do |row|
|
54
|
+
"| #{row.join(' | ')} |"
|
55
|
+
end
|
56
|
+
|
57
|
+
separator = '-' * rows.first.length
|
58
|
+
result = rows.join("\n#{separator}\n")
|
59
|
+
"#{separator}\n#{result}\n#{separator}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def pad_rows(rows, column_widths)
|
63
|
+
rows.map do |row|
|
64
|
+
row.map.with_index do |col, index|
|
65
|
+
col.ljust(column_widths[index], ' ')
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def find_column_widths(rows)
|
71
|
+
rows.each_with_object([]) do |row, ret|
|
72
|
+
row.each_with_index do |col, index|
|
73
|
+
ret[index] ||= []
|
74
|
+
ret[index] << col.length
|
75
|
+
end
|
76
|
+
end.map(&:max)
|
77
|
+
end
|
78
|
+
|
79
|
+
def build_locale_rows(locales, phrase_count)
|
80
|
+
[HEADER] + locales.map do |locale|
|
81
|
+
build_locale_table_row(locale, phrase_count)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def build_locale_table_row(locale, phrase_count)
|
86
|
+
[
|
87
|
+
locale['locale'], phrase_count.to_i.to_s,
|
88
|
+
locale['translated_count'].to_i.to_s,
|
89
|
+
locale['percent_translated'].to_f.to_s
|
90
|
+
]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Rosette
|
4
|
+
module Client
|
5
|
+
module Commands
|
6
|
+
|
7
|
+
autoload :DiffCommand, 'rosette/client/commands/diff_command'
|
8
|
+
autoload :DiffCommandArgs, 'rosette/client/commands/diff_command'
|
9
|
+
autoload :ShowCommand, 'rosette/client/commands/show_command'
|
10
|
+
autoload :ShowCommandArgs, 'rosette/client/commands/show_command'
|
11
|
+
autoload :StatusCommand, 'rosette/client/commands/status_command'
|
12
|
+
autoload :StatusCommandArgs, 'rosette/client/commands/status_command'
|
13
|
+
autoload :CommitCommand, 'rosette/client/commands/commit_command'
|
14
|
+
autoload :CommitCommandArgs, 'rosette/client/commands/commit_command'
|
15
|
+
autoload :SnapshotCommand, 'rosette/client/commands/snapshot_command'
|
16
|
+
autoload :SnapshotCommandArgs, 'rosette/client/commands/snapshot_command'
|
17
|
+
autoload :RepoSnapshotCommand, 'rosette/client/commands/repo_snapshot_command'
|
18
|
+
autoload :RepoSnapshotCommandArgs, 'rosette/client/commands/repo_snapshot_command'
|
19
|
+
|
20
|
+
class Command
|
21
|
+
attr_reader :api, :terminal, :repo
|
22
|
+
|
23
|
+
def initialize(api, terminal, repo)
|
24
|
+
@api = api
|
25
|
+
@terminal = terminal
|
26
|
+
@repo = repo
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def print_hash(hash)
|
32
|
+
hash.each_pair do |key, value|
|
33
|
+
terminal.say("#{key}: #{value}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def handle_error(response)
|
38
|
+
if response.error?
|
39
|
+
terminal.say(
|
40
|
+
[response.error, response.detail].compact.join(': ')
|
41
|
+
)
|
42
|
+
else
|
43
|
+
yield response if block_given?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def group_diff_by_file(diff)
|
48
|
+
result = Hash.new do |h, i|
|
49
|
+
h[i] = Hash.new do |h2, i2|
|
50
|
+
h2[i2] = []
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
diff.each_with_object(result) do |(state, items), by_path|
|
55
|
+
items.each do |item|
|
56
|
+
by_path[item['file']][state] << item
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def derive_repo_name
|
62
|
+
File.basename(`git config --get remote.origin.url`.strip).gsub(/\.git\z/, '')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|