bin/crowdin-cli in crowdin-cli-0.2.5 vs bin/crowdin-cli in crowdin-cli-0.3.0

- old
+ new

@@ -77,11 +77,11 @@ } placeholders = pattern.inject([]){ |memo, h| memo << h.first[/%(.*)%/, 1] } unless languages_mapping.nil? - pattern = Hash[pattern.map{ |placeholder, str| [ + pattern = Hash[pattern.map { |placeholder, str| [ placeholder, (languages_mapping[placeholder[/%(.*)%/, 1]][lang['crowdin_code']] rescue nil) || str] }] end @@ -227,11 +227,10 @@ # files that exists in archive and doesn't match current project configuration unmatched_files = [] Zip::File.open(zipfile_name) do |zipfile| zipfile.select{ |zip_entry| zip_entry.file? }.each do |f| - # XXX # `f' - relative path in archive file = files_list[f.name] if file fpath = File.join(dest_path, file) FileUtils.mkdir_p(File.dirname(fpath)) @@ -243,15 +242,64 @@ end end unless unmatched_files.empty? puts "Warning: Downloaded translations does not match current project configuration. Some of the resulted files will be omitted." - unmatched_files.each{ |file| puts " - `#{file}'" } + unmatched_files.each { |file| puts " - `#{file}'" } puts "Crowdin has internal caching mechanisms that prevents us from overload. Please try to download translations later." end end +# Build a Hash tree from Array of +filenames* +# +def build_hash_tree(filenames) + files_tree = filenames.inject({}) { |h, i| t = h; i.split("/").each { |n| t[n] ||= {}; t = t[n] }; h } +end + +# Box-drawing character - https://en.wikipedia.org/wiki/Box-drawing_character +# ├ └ ─ │ +# +def display_tree(files_tree, level = -2, branches = []) + tab = ' ' * 4 + level += 1 + + files_tree.each_with_index do |(key, val), index| + if val.empty? # this is a file + result = branches.take(level).inject('') { |s, i| s << (i == 1 ? '│ ': ' ') } + + if index == files_tree.length - 1 + # this is a last element + result << '└' + '── ' + key + else + result << '├' + '── ' + key + end + + puts result + else # this is directory + if key == '' # root directory + result = '.' + else + result = branches.take(level).inject('') { |s, i| s << (i == 1 ? '│ ' : ' ') } + if index == files_tree.length - 1 + # this is a last element + result << '└' + '── ' + key + + branches[level] = 0 + else + result << '├' + '── ' + key + + branches[level] = 1 + end + end + puts result + + # recursion \(^_^)/ + display_tree(val, level, branches) + end + end +end + ### include GLI::App version Crowdin::CLI::VERSION @@ -287,11 +335,11 @@ source_language = project_info['details']['source_language']['code'] # Crowdin supported languages list supported_languages = @crowdin.supported_languages - source_language = supported_languages.find{ |lang| lang['crowdin_code'] == source_language } + source_language = supported_languages.find { |lang| lang['crowdin_code'] == source_language } remote_project_tree = get_remote_files_hierarchy(project_info['files']) local_files = [] dest_files = [] @@ -317,17 +365,17 @@ else Find.find(@base_path) do |source_path| dest = source_path.sub(@base_path, '') # relative path in Crowdin if File.directory?(source_path) - if ignores.any?{ |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } + if ignores.any? { |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } Find.prune # Don't look any further into this directory else next end elsif File.fnmatch?(file['source'], dest, File::FNM_PATHNAME) - next if ignores.any?{ |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } + next if ignores.any? { |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } dest_files << dest export_pattern = construct_export_pattern(dest, file['source'], file['translation']) @@ -352,13 +400,13 @@ EOS end common_dir = @preserve_hierarchy ? '' : find_common_directory_path(dest_files) - local_project_tree = get_local_files_hierarchy(local_files.collect{ |h| h[:dest].sub(common_dir, '') }) + local_project_tree = get_local_files_hierarchy(local_files.collect { |h| h[:dest].sub(common_dir, '') }) - local_files.each{ |file| file[:dest].sub!(common_dir, '') } + local_files.each { |file| file[:dest].sub!(common_dir, '') } # Create directory tree # create_dirs = local_project_tree[:dirs] - remote_project_tree[:dirs] create_dirs.each do |dir| @@ -369,11 +417,11 @@ if options['auto-update'] # Update existing files in Crowdin project # # array containing elements common to the two arrays update_files = local_project_tree[:files] & remote_project_tree[:files] - files_for_upload = local_files.select{ |file| update_files.include?(file[:dest]) } + files_for_upload = local_files.select { |file| update_files.include?(file[:dest]) } files_for_upload.each do |file| print "Updating source file `#{file[:dest]}'" params = {} params[:scheme] = file.delete(:sheme) @@ -392,11 +440,11 @@ end # Add new files to Crowdin project # add_files = local_project_tree[:files] - remote_project_tree[:files] - files_for_add = local_files.select{ |file| add_files.include?(file[:dest]) } + files_for_add = local_files.select { |file| add_files.include?(file[:dest]) } files_for_add.each do |file| print "Uploading source file `#{file[:dest]}'" params = {} params[:scheme] = file.delete(:sheme) @@ -406,11 +454,11 @@ puts "\rUploading source file `#{file[:dest]}' - OK" end end # action - end # command + end # upload sources c.desc I18n.t('app.commands.upload.commands.translations.desc') c.long_desc I18n.t('app.commands.upload.commands.translations.long_desc') c.command :translations do |c| @@ -438,25 +486,26 @@ project_info = @crowdin.project_info remote_project_tree = get_remote_files_hierarchy(project_info['files']) - project_languages = project_info['languages'].collect{ |h| h['code'] } - if language != 'all' + if language == 'all' + project_languages = project_info['languages'].collect { |h| h['code'] } + else if project_languages.include?(language) project_languages = [] << language else exit_now!("language '#{language}' doesn't exist in a project") end end supported_languages = @crowdin.supported_languages source_language = project_info['details']['source_language']['code'] - source_language = supported_languages.find{ |lang| lang['crowdin_code'] == source_language } + source_language = supported_languages.find { |lang| lang['crowdin_code'] == source_language } - translation_languages = supported_languages.select{ |lang| project_languages.include?(lang['crowdin_code']) } + translation_languages = supported_languages.select { |lang| project_languages.include?(lang['crowdin_code']) } translated_files = Hash.new{ |hash, key| hash[key] = Array.new } dest_files = [] @config['files'].each do |file| @@ -488,17 +537,17 @@ else Find.find(@base_path) do |source_path| dest = source_path.sub(@base_path, '') # relative path in Crowdin if File.directory?(source_path) - if ignores.any?{ |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } + if ignores.any? { |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } Find.prune # Don't look any further into this directory else next end elsif File.fnmatch?(file['source'], dest, File::FNM_PATHNAME) - next if ignores.any?{ |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } + next if ignores.any? { |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } dest_files << dest export_pattern = construct_export_pattern(dest, file['source'], file['translation']) @@ -547,42 +596,198 @@ end end end end # action - end # command + end # upload translations end +desc I18n.t('app.commands.list.desc') +long_desc I18n.t('app.commands.list.long_desc') +command :list do |ls_cmd| + + ls_cmd.desc I18n.t('app.commands.list.commands.project.desc') + ls_cmd.command :project do |proj_cmd| + proj_cmd.desc I18n.t('app.commands.list.switches.tree.desc') + proj_cmd.switch ['tree'], :negatable => false + + proj_cmd.action do |global_options, options, args| + project_info = @crowdin.project_info + remote_project_tree = get_remote_files_hierarchy(project_info['files']) + + if options[:tree] + tree = build_hash_tree(remote_project_tree[:files]) + display_tree(tree) + else + puts remote_project_tree[:files] + end + end + end + + ls_cmd.desc I18n.t('app.commands.list.commands.sources.desc') + ls_cmd.command :sources do |src_cmd| + src_cmd.desc I18n.t('app.commands.list.switches.tree.desc') + src_cmd.switch ['tree'], :negatable => false + + src_cmd.action do |global_options, options, args| + local_files = [] + dest_files = [] + + @config['files'].each do |file| + get_invalid_placeholders(file['translation']).each do |placeholder| + puts "Warning: #{placeholder} is not valid variable supported by Crowdin. See http://crowdin.net/page/cli-tool#configuration-file for more details." + end + + ignores = file['ignore'] || [] + + if File.exist?(File.join(@base_path, file['source'])) + dest = file['source'] + dest_files << dest + + local_file = { dest: dest, source: File.join(@base_path, file['source']), export_pattern: file['translation'] } + + local_file.merge!({ sheme: file['scheme'] }) if file.has_key?('scheme') + local_file.merge!({ first_line_contains_header: file['first_line_contains_header'] }) if file.has_key?('first_line_contains_header') + local_file.merge!({ update_option: file['update_option'] }) if file.has_key?('update_option') + + local_files << local_file + else + Find.find(@base_path) do |source_path| + dest = source_path.sub(@base_path, '') # relative path in Crowdin + + if File.directory?(source_path) + if ignores.any? { |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } + Find.prune # Don't look any further into this directory + else + next + end + elsif File.fnmatch?(file['source'], dest, File::FNM_PATHNAME) + next if ignores.any? { |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } + + dest_files << dest + + export_pattern = construct_export_pattern(dest, file['source'], file['translation']) + + local_file = { dest: dest, source: source_path, export_pattern: export_pattern } + + local_file.merge!({ sheme: file['scheme'] }) if file.has_key?('scheme') + local_file.merge!({ first_line_contains_header: file['first_line_contains_header'] }) if file.has_key?('first_line_contains_header') + local_file.merge!({ update_option: file['update_option'] }) if file.has_key?('update_option') + + local_files << local_file + end + end # Find + + end # if File.exists? + end # @config['files'] + + common_dir = @preserve_hierarchy ? '' : find_common_directory_path(dest_files) + + local_project_tree = get_local_files_hierarchy(local_files.collect { |h| h[:dest].sub(common_dir, '') }) + + if options[:tree] + tree = build_hash_tree(local_project_tree[:files]) + display_tree(tree) + else + puts local_project_tree[:files] + end + end + end # list sources + + ls_cmd.desc I18n.t('app.commands.list.commands.translations.desc') + ls_cmd.command :translations do |trans_cmd| + trans_cmd.desc I18n.t('app.commands.list.switches.tree.desc') + trans_cmd.switch ['tree'], :negatable => false + + trans_cmd.action do |global_options, options, args| + project_info = @crowdin.project_info + + project_languages = project_info['languages'].collect{ |h| h['code'] } + + supported_languages = @crowdin.supported_languages + translation_languages = supported_languages.select { |lang| project_languages.include?(lang['crowdin_code']) } + + translation_files = [] + @config['files'].each do |file| + languages_mapping = file['languages_mapping'] # Hash or NilClass + + ignores = file['ignore'] || [] + + if File.exists?(File.join(@base_path, file['source'])) + dest = file['source'].sub("#{@base_path}", '') + + translation_languages.each do |lang| + local_file = export_pattern_to_path(dest, file['translation'], lang, languages_mapping) + translations_files << local_file + end + + else + Find.find(@base_path) do |source_path| + dest = source_path.sub(@base_path, '') # relative path in Crowdin + + if File.directory?(source_path) + if ignores.any? { |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } + Find.prune # Don't look any further into this directory + else + next + end + elsif File.fnmatch?(file['source'], dest, File::FNM_PATHNAME) + next if ignores.any? { |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } + + export_pattern = construct_export_pattern(dest, file['source'], file['translation']) + + translation_languages.each do |lang| + local_file = export_pattern_to_path(dest, export_pattern, lang, languages_mapping) + translation_files << local_file + end + + end + end # Find + end # if + end # @config['files'] + + if options[:tree] + tree = build_hash_tree(translation_files) + display_tree(tree) + else + puts translation_files + end + + end + end # list translations + + #ls_cmd.default_command :project +end # list + desc I18n.t('app.commands.download.desc') #arg_name 'Describe arguments to download here' command :download do |c| c.desc I18n.t('app.commands.download.flags.language.desc') + c.long_desc I18n.t('app.commands.download.flags.language.long_desc') c.arg_name 'language_code' c.flag [:l, :language], :default_value => 'all' c.action do |global_options ,options, args| language = options[:language] supported_languages = @crowdin.supported_languages project_info = @crowdin.project_info - remote_project_tree = get_remote_files_hierarchy(project_info['files']) + if language == 'all' + project_languages = project_info['languages'].collect{ |h| h['code'] } - project_languages = project_info['languages'].collect{ |h| h['code'] } - - if @jipt_language - if supported_languages.find{ |lang| lang['crowdin_code'] == @jipt_language } - project_languages << @jipt_language # crowdin_language_code - else - exit_now!("invalid jipt language `#{@jipt_language}`") + if @jipt_language + if supported_languages.find { |lang| lang['crowdin_code'] == @jipt_language } + project_languages << @jipt_language # crowdin_language_code + else + exit_now!("invalid jipt language `#{@jipt_language}`") + end end - end - - if language != 'all' + else if project_languages.include?(language) project_languages = [] << language else exit_now!("language '#{language}' doesn't exist in a project") end @@ -590,13 +795,13 @@ # use export API method before to download the most recent translations @crowdin.export_translations source_language = project_info['details']['source_language']['code'] - source_language = supported_languages.find{ |lang| lang['crowdin_code'] == source_language } + source_language = supported_languages.find { |lang| lang['crowdin_code'] == source_language } - translation_languages = supported_languages.select{ |lang| project_languages.include?(lang['crowdin_code']) } + translation_languages = supported_languages.select { |lang| project_languages.include?(lang['crowdin_code']) } # keys is all possible files in .ZIP archive # values is resulted local files downloadable_files_hash = {} @@ -627,17 +832,17 @@ else Find.find(@base_path) do |source_path| dest = source_path.sub(@base_path, '') # relative path in Crowdin if File.directory?(source_path) - if ignores.any?{ |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } + if ignores.any? { |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } Find.prune # Don't look any further into this directory else next end elsif File.fnmatch?(file['source'], dest, File::FNM_PATHNAME) - next if ignores.any?{ |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } + next if ignores.any? { |pattern| File.fnmatch?(pattern, dest, File::FNM_PATHNAME) } export_pattern = construct_export_pattern(dest, file['source'], file['translation']) file_translation_languages.each do |lang| zipped_file = export_pattern_to_path(dest, export_pattern, lang) @@ -660,12 +865,12 @@ unzip_file_with_translations(zipfile_name, @base_path, downloadable_files_hash) ensure tempfile.close tempfile.unlink # delete the tempfile end - end -end + end # action +end # download pre do |globals ,command, options, args| # Pre logic here # Return true to proceed; false to abourt and not call the # chosen command