rosette-client 1.0.0
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.
- 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
|