From 017540338e6ca4ae1e753f3577dfcc4650576008 Mon Sep 17 00:00:00 2001 From: Kowalski Dark Date: Sat, 27 Feb 2021 02:38:25 +0800 Subject: [PATCH 1/3] Move to 0.0.5 --- .github/workflows/test.yml | 33 ++++ .gitignore | 3 +- .rubocop.yml | 17 ++ Gemfile | 4 +- README.md | 13 +- Rakefile | 15 +- azure-pipelines.yml | 21 --- bin/rien | 5 +- lib/rien.rb | 13 +- lib/rien/cli.rb | 232 ------------------------- lib/rien/cli/cli.rb | 82 +++++++++ lib/rien/cli/helper.rb | 208 ++++++++++++++++++++++ lib/rien/configurable.rb | 78 +++++---- lib/rien/const.rb | 26 +-- lib/rien/core_ext/string.rb | 5 +- lib/rien/decoder.rb | 33 ++-- lib/rien/encoder.rb | 43 +++-- lib/rien/error.rb | 40 +++++ lib/rien/version.rb | 4 +- rien.gemspec | 18 +- test/{unit => }/cli_helper_test.rb | 7 +- test/{unit => }/encoder_test.rb | 6 +- test/samples/autoload_gem.rb | 4 +- test/samples/dir/ruby_in_dir.rb | 4 +- test/samples/load_plain.rb | 4 +- test/samples/not_ruby.rb | 2 +- test/samples/plain.rb | 4 +- test/samples/read_eval_plain.rb | 6 +- test/samples/require_gem.rb | 4 +- test/samples/require_relative_plain.rb | 4 +- test/test_helper.rb | 9 +- 31 files changed, 583 insertions(+), 364 deletions(-) create mode 100644 .github/workflows/test.yml create mode 100644 .rubocop.yml delete mode 100644 azure-pipelines.yml delete mode 100644 lib/rien/cli.rb create mode 100644 lib/rien/cli/cli.rb create mode 100644 lib/rien/cli/helper.rb create mode 100644 lib/rien/error.rb rename test/{unit => }/cli_helper_test.rb (96%) rename test/{unit => }/encoder_test.rb (83%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..001a076 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,33 @@ +name: CI Tests +on: + pull_request: + push: + branches: + - master + - dev + schedule: + - cron: "0 7 * * SUN" +jobs: + test: + strategy: + fail-fast: false + matrix: + include: + - { os: ubuntu-20.04, ruby: "3.0" } + - { os: macos-10.15, ruby: "3.0" } + - { os: windows-2019, ruby: "3.0" } + name: test ${{ matrix.os }} ${{ matrix.ruby }} + runs-on: ${{ matrix.os }} + timeout-minutes: 5 + steps: + - uses: actions/checkout@v2 + - uses: ruby/setup-ruby@master + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: false + - name: Install Dependencies + run: | + gem install bundler + bundle install --jobs 4 --retry 3 + - name: Test + run: rake test diff --git a/.gitignore b/.gitignore index 587825c..ba5a729 100644 --- a/.gitignore +++ b/.gitignore @@ -43,9 +43,10 @@ build-iPhoneSimulator/ # for a library or gem, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: -# Gemfile.lock +Gemfile.lock # .ruby-version # .ruby-gemset # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: .rvmrc +dev*.rb diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..2d7c6fb --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,17 @@ +AllCops: + NewCops: enable + Exclude: + - tmp/**/* + - pkg/**/* + - test/samples/**/* + - rien_output/**/* +Style/Documentation: + Enabled: false +Metrics/MethodLength: + Enabled: false +Metrics/ModuleLength: + Enabled: false +Metrics/AbcSize: + Enabled: false +Metrics/BlockLength: + Enabled: false diff --git a/Gemfile b/Gemfile index d5708d9..e485563 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,6 @@ -source "https://rubygems.org" +# frozen_string_literal: true + +source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } # Declare your gem's dependencies in flow_core.gemspec. diff --git a/README.md b/README.md index 3be562c..b99dd03 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,13 @@ Ruby IR Encoding Gem (Experimental) -[![Build Status](https://dev.azure.com/dsh0416/rien/_apis/build/status/coderemixer.rien?branchName=master)](https://dev.azure.com/dsh0416/rien/_build/latest?definitionId=1&branchName=master) +[![CI Tests](https://github.com/coderemixer/rien/workflows/CI%20Tests/badge.svg)](https://github.com/coderemixer/rien/actions?query=workflow%3A%22CI+Tests%22) # Example ``` Usage: rien [options] + -v, --version Show current version -e, --encode [FILE] Encode specific ruby file -p, --pack [DIR] Pack ruby directory into encoded files -o, --out [FILE/DIR] Indicate the output of the encoded file(s) @@ -71,6 +72,14 @@ Rien.configure do |config| # aka. /tmp/rien for linux config.tmpdir = "tmpdir/rien" + # Ruar: https://github.com/DarkKowalski/ruar + # [Optional] Ruar mode + config.ruar = true + # Set key/iv or use generated ones + config.ruar_key = Base64.encode64(your_key_binary) + config.ruar_iv = Base64.encode64(your_iv_binary) + # You must set auth data + config.ruar_auth_data = Base64.encode64(your_auth_data) end ``` @@ -101,4 +110,4 @@ Use `Rinefile` to exclude `lib/plugins/**/init.rb` Rien uses a `tmpdir` to store intermediate results and timestamps to distinguish them. -Check your `tmpdir` (`/tmp/rien` for linux by default) to clean unsuccessful build results. \ No newline at end of file +Check your `tmpdir` (`/tmp/rien` for linux by default) to clean unsuccessful build results. diff --git a/Rakefile b/Rakefile index e73f7b4..301a647 100644 --- a/Rakefile +++ b/Rakefile @@ -1,12 +1,13 @@ +# frozen_string_literal: true + require 'bundler/gem_tasks' require 'rake/testtask' -require 'ci/reporter/rake/minitest' -Rake::TestTask.new(:minitest) do |t| - t.libs << "lib" - t.libs << "test" - t.test_files = FileList['test/**/*_test.rb'] +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.libs << 'test' + t.test_files = FileList['test/**/*_test.rb'].exclude('test/samples') + t.verbose = true end -task :minitest => 'ci:setup:minitest' -task :default => 'minitest' +task default: %w[test] diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 01086dc..0000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,21 +0,0 @@ -pool: - vmImage: 'Ubuntu 20.04' - -steps: -- task: UseRubyVersion@0 - inputs: - versionSpec: '>= 2.7.1' - -- script: | - gem install bundler - bundle install --retry=3 --jobs=4 - displayName: 'bundle install' - -- script: bundle exec rake - displayName: 'bundle exec rake' - -- task: PublishTestResults@2 - condition: succeededOrFailed() - inputs: - testResultsFiles: '**/reports/TEST-*.xml' - testRunTitle: 'Rien Minitest' diff --git a/bin/rien b/bin/rien index 004e149..a9f1e88 100755 --- a/bin/rien +++ b/bin/rien @@ -1,5 +1,6 @@ #!/bin/ruby +# frozen_string_literal: true -require "rien" +require 'rien' -Rien::Cli.new.start \ No newline at end of file +Rien::Cli.new.start diff --git a/lib/rien.rb b/lib/rien.rb index a91bbf5..359a03d 100644 --- a/lib/rien.rb +++ b/lib/rien.rb @@ -1,13 +1,24 @@ +# frozen_string_literal: true + +require 'fileutils' +require 'optparse' +require 'tmpdir' require 'zlib' +require 'ruar' + +require 'ruby-progressbar' + require_relative 'rien/core_ext/string' require_relative 'rien/version' require_relative 'rien/const' +require_relative 'rien/error' require_relative 'rien/configurable' require_relative 'rien/decoder' require_relative 'rien/encoder' -require_relative 'rien/cli' +require_relative 'rien/cli/helper' +require_relative 'rien/cli/cli' diff --git a/lib/rien/cli.rb b/lib/rien/cli.rb deleted file mode 100644 index 0bb95d2..0000000 --- a/lib/rien/cli.rb +++ /dev/null @@ -1,232 +0,0 @@ -require "optparse" -require "ruby-progressbar" -require "fileutils" - -module Rien::CliHelper - class CliHelperStatus - attr_accessor :silent - - def initialize - @silent = false - end - end - - private def status - @status ||= CliHelperStatus.new - end - - private def encoder - @encoder ||= Rien::Encoder.new - end - - private def wait_user_on_encoded(path) - if path.match(".rbc") && !status.silent - print "\n#{path} maybe have already been encoded, continue? (a/y/n) ".yellow - user_input = STDIN.gets.chomp.downcase - if user_input == "a" - status.silent = true # skip all warnings - elsif user_input == "y" - # ignore - else - abort("Manually abort".red) - end - end - end - - # Notice: - # this path must be relative path, - # or it would break after moving to another directory - private def encode(path) - wait_user_on_encoded(path) - - begin - bytes = encoder.encode_file(path) - rescue Exception => e - abort "\nFailed to encode #{path}, reason:\n#{e.message}".red - end - - bytes - end - - private def export_single_encoded(source, output) - bytes = encode(source) - - File.open("#{output}.rbc", "wb") do |f| - f.write bytes - end - - File.open(output, "w") do |f| - f.write encoder.bootstrap - end - end - - private def replace_with_encoded(path) - bytes = encode(path) - - # Write encoded file - File.open("#{path}.rbc", "wb") do |f| - f.write bytes - end - - # Replace file with bootstrap - FileUtils.rm(path) - File.open(path, "w") do |f| - f.write encoder.bootstrap - end - end - - private def pack_files(paths) - progressbar = ProgressBar.create(:title => "Generating", - :starting_at => 0, - :length => 80, - :total => paths.length, - :smoothing => 0.6, - :format => "%t |%b>>%i| %p%% %a") - - paths.each do |path| - progressbar.log("Compiling: #{path}") - replace_with_encoded(path) # Wirte encoded file and replace the orginal ruby source file with bootstrap - progressbar.increment - end - end - - private def copy_dir(source, output) - FileUtils.mkdir_p output - FileUtils.cp_r File.join(source, "."), output - rescue Exception => e - abort("\nFailed to copy #{source} to #{output}, reason: #{e.message}".red) - end - - private def move_dir(source, output) - FileUtils.mv "#{source}", output - rescue Exception => e - abort("\nFailed to move #{source} to #{output}, reason: #{e.message}".red) - end - - private def pack_all_files_in_directory(source, output, tmpdir) - # Copy to temp workspace - time_stamp = Time.now.strftime("%Y%m%d%H%M%S") - temp_workspace = File.expand_path(time_stamp, tmpdir) - copy_dir(source, temp_workspace) - - # Change to temp workspace - Dir.chdir(temp_workspace) do - # Encode - files = Dir["./**/*.rb"] # pack all files - pack_files(files) - puts "Successed to compile and pack #{source} into #{output}\ntotal #{files.length} file(s)".green - end - - # Clean up - move_dir(temp_workspace, output) - end - - private def use_rienfile_to_pack(source) - # Eval Rienfile - begin - rienfile = File.expand_path("Rienfile", source) - load rienfile - rescue Exception => e - abort "\nFailed to load Rienfile, reason:\n#{e.message}".red - end - - # Configure - status.silent = Rien.config.silent - output = Rien.config.output - tmpdir = Rien.config.tmpdir - - # Copy to temp workspace - time_stamp = Time.now.strftime("%Y%m%d%H%M%S") - temp_workspace = File.expand_path(time_stamp, tmpdir) - copy_dir(source, temp_workspace) - - # Change to temp workspace - source_dir = File.absolute_path(File.dirname(source)) - Dir.chdir(temp_workspace) - - # Encode - files = Rien.config.effective_paths - pack_files(files) - - # Clean up - puts "Successed to compile and pack #{source} into #{output}\n" \ - "using #{rienfile}\n" \ - "total #{files.length} file(s)".green - Dir.chdir(source_dir) - move_dir(temp_workspace, output) - end -end - -class Rien::Cli - include Rien::CliHelper - - def initialize - @options = { - mode: :help, - } - - @parser = OptionParser.new do |opts| - opts.banner = "Usage: rien [options]" - opts.on("-e", "--encode [FILE]", "Encode specific ruby file", String) do |v| - @options[:mode] = :encode - @options[:file] = v - @options[:output] ||= "output.rb" - end - - opts.on("-p", "--pack [DIR]", "Pack ruby directory into encoded files", String) do |v| - @options[:mode] = :pack - @options[:file] = v - @options[:output] ||= "rien_output" - @options[:tmpdir] ||= "/tmp/rien" - end - - opts.on("-o", "--out [FILE/DIR]", "Indicate the output of the encoded file(s)", String) do |v| - @options[:output] = v - end - - opts.on("-u", "--use-rienfile", "Use Rienfile to configure, override other options", String) do - @options[:rienfile] = true - end - - opts.on("-s", "--silent-mode", "Suppress all prompts asking for user input", String) do - @options[:silent] = true - end - - opts.on("-t", "--tmpdir [DIR]", "Select a temp directory to store intermediate results", String) do |v| - @options[:tmpdir] = v - end - end - end - - def start - @parser.parse! - case @options[:mode] - when :encode - source = @options[:file] - output = @options[:output] - status.silent = @options[:silent] - - export_single_encoded(source, output) - - puts "Successed to compile #{source} into #{output} and #{output}.rbc".green - when :pack - source = @options[:file] - abort("\nOnly directory can be packed".red) unless File.directory?(source) - - use_rienfile = @options[:rienfile] - if use_rienfile # Ignore other options from CLI - use_rienfile_to_pack(source) - else # Use options from CLI - output = @options[:output] - tmpdir = @options[:tmpdir] - status.silent = @options[:silent] - - pack_all_files_in_directory(source, output, tmpdir) - end - when :help - puts @parser - else - puts @parser - end - end -end diff --git a/lib/rien/cli/cli.rb b/lib/rien/cli/cli.rb new file mode 100644 index 0000000..96517d7 --- /dev/null +++ b/lib/rien/cli/cli.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +module Rien + class Cli + include Rien::CliHelper + + def initialize + @options = { + mode: :help + } + + @parser = OptionParser.new do |opts| + opts.banner = 'Usage: rien [options]' + opts.on('-e', '--encode [FILE]', 'Encode specific ruby file', String) do |v| + @options[:mode] = :encode + @options[:file] = v + @options[:output] ||= 'output.rb' + end + + opts.on('-p', '--pack [DIR]', 'Pack ruby directory into encoded files', String) do |v| + @options[:mode] = :pack + @options[:file] = v + @options[:output] ||= 'rien_output' + @options[:tmpdir] ||= '/tmp/rien' + end + + opts.on('-o', '--out [FILE/DIR]', 'Indicate the output of the encoded file(s)', String) do |v| + @options[:output] = v + end + + opts.on('-u', '--use-rienfile', 'Use Rienfile to configure, override other options', String) do + @options[:rienfile] = true + end + + opts.on('-s', '--silent-mode', 'Suppress all prompts asking for user input', String) do + @options[:silent] = true + end + + opts.on('-t', '--tmpdir [DIR]', 'Select a temp directory to store intermediate results', String) do |v| + @options[:tmpdir] = v + end + + opts.on('-v', '--version', 'Show current version') do + @options[:mode] = :version + end + end + end + + def start + @parser.parse! + case @options[:mode] + when :encode + source = @options[:file] + output = @options[:output] + status.silent = @options[:silent] + + export_single_encoded(source, output) + + puts "Successed to compile #{source} into #{output} and #{output}.rbc".green + when :pack + source = @options[:file] + abort("\nOnly directory can be packed".red) unless File.directory?(source) + + use_rienfile = @options[:rienfile] + if use_rienfile # Ignore other options from CLI + puts 'Use Rienfile'.green + use_rienfile_to_pack(source) + else # Use options from CLI + output = @options[:output] + tmpdir = @options[:tmpdir] + status.silent = @options[:silent] + + pack_all_files_in_directory(source, output, tmpdir) + end + when :version + puts Rien::VERSION.to_s + else + puts @parser + end + end + end +end diff --git a/lib/rien/cli/helper.rb b/lib/rien/cli/helper.rb new file mode 100644 index 0000000..b2266ac --- /dev/null +++ b/lib/rien/cli/helper.rb @@ -0,0 +1,208 @@ +# frozen_string_literal: true + +module Rien + module CliHelper + class CliHelperStatus + attr_accessor :silent + + def initialize + @silent = false + end + end + + def self.make_failed_to_encode_error(path, reason) + Rien::Error::FailedToEncode.new(path, reason) + end + + def self.make_failed_to_move_error(path, reason) + Rien::Error::FailedToMove.new(path, reason) + end + + def self.make_failed_to_copy_error(path, reason) + Rien::Error::FailedToCopy.new(path, reason) + end + + def self.make_failed_to_load_rienfile_error(path, reason) + Rien::Error::FailedToLoadRienfile.new(path, reason) + end + + private + + def status + @status ||= CliHelperStatus.new + end + + def encoder + @encoder ||= Rien::Encoder.new + end + + def wait_user_on_encoded(path) + return unless path.match('.rbc') && !status.silent + + path.match('.rbc') && !status.silent + print "\n#{path} maybe have already been encoded, continue? (a/y/n) ".yellow + user_input = $stdin.gets.chomp.downcase + case user_input + when 'a' + status.silent = true # skip all warnings + when 'y' + # ignore + else + abort('Manually abort'.red) + end + end + + # Notice: + # this path must be relative path, + # or it would break after moving to another directory + def encode(path) + wait_user_on_encoded(path) + + begin + bytes = encoder.encode_file(path) + rescue SyntaxError => e + raise Rien::CliHelper.make_failed_to_encode_error(path, e.message) + end + + bytes + end + + def export_single_encoded(source, output, mode: :plain) + bytes = encode(source) + + File.open("#{output}.rbc", 'wb') do |f| + f.write bytes + end + + File.open(output, 'w') do |f| + f.write encoder.bootstrap(mode: mode) + end + end + + def replace_with_encoded(path, mode: :plain) + bytes = encode(path) + + # Write encoded file + File.open("#{path}.rbc", 'wb') do |f| + f.write bytes + end + + # Replace file with bootstrap + FileUtils.rm(path) + File.open(path, 'w') do |f| + f.write encoder.bootstrap(mode: mode) + end + end + + def pack_files(paths, mode: :plain) + progressbar = ProgressBar.create(title: 'Generating', + starting_at: 0, + length: 80, + total: paths.length, + smoothing: 0.6, + format: '%t |%b>>%i| %p%% %a') + + paths.each do |path| + progressbar.log("Compiling: #{path}") + replace_with_encoded(path, mode: mode) + progressbar.increment + end + end + + def copy_dir(source, output) + FileUtils.mkdir_p output + FileUtils.cp_r File.join(source, '.'), output + rescue StandardError => e + raise Rien::CliHelper.make_failed_to_copy_error(source, e.message) + end + + def move_dir(source, output) + FileUtils.mv source.to_s, output + rescue StandardError => e + raise Rien::CliHelper.make_failed_to_move_error(source, e.message) + end + + def pack_all_files_in_directory(source, output, tmpdir, mode: :plain) + # Copy to temp workspace + time_stamp = Time.now.strftime('%Y%m%d%H%M%S') + temp_workspace = File.expand_path(time_stamp, tmpdir) + copy_dir(source, temp_workspace) + + # Change to temp workspace + msg = '' + Dir.chdir(temp_workspace) do + # Encode + # pack all files + files = Dir['./**/*.rb'] + pack_files(files, mode: mode) + + msg = <<~MSG + Successed to compile and pack #{source} into #{output} + total #{files.length} file(s) + MSG + end + + move_dir(temp_workspace, output) + + puts msg.green + end + + def use_ruar_to_serialize(source, output) + ruar_key = Rien.config.ruar_key + ruar_iv = Rien.config.ruar_iv + ruar_auth_data = Rien.config.ruar_auth_data + + warn 'Ruar: Empty key, generate a new one'.yellow if ruar_key.nil? + warn 'Ruar: Empty initialization vector, generate a new one'.yellow if ruar_iv.nil? + if ruar_auth_data.nil? + warn 'Ruar: You must set ruar_auth_data, abort!'.red + return + end + + Ruar.cipher.setup(key: ruar_key, iv: ruar_iv, auth_data: ruar_auth_data) + Ruar::Serialize.aead(source, output) + end + + def use_rienfile_to_pack(source) + # Eval Rienfile + begin + rienfile = File.expand_path('Rienfile', source) + load rienfile + rescue StandardError => e + raise Rien::CliHelper.make_failed_to_load_rienfile_error(rienfile, e.message) + end + + # Configure + status.silent = Rien.config.silent + output = Rien.config.output + tmpdir = Rien.config.tmpdir + ruar = Rien.config.ruar + + # Copy to temp workspace + time_stamp = Time.now.strftime('%Y%m%d%H%M%S') + temp_workspace = File.expand_path(time_stamp, tmpdir) + copy_dir(source, temp_workspace) + + # Change to temp workspace + msg = '' + Dir.chdir(temp_workspace) do + # Encode + files = Rien.config.effective_paths + if ruar + pack_files(files, mode: :ruar) + else + pack_files(files, mode: :plain) + end + + msg = <<~MSG + Successed to compile and pack #{source} into #{output} + using #{rienfile} + total #{files.length} file(s) + MSG + end + move_dir(temp_workspace, output) + puts msg.green + use_ruar_to_serialize(output, "#{output}.ruar") if ruar + end + end +end diff --git a/lib/rien/configurable.rb b/lib/rien/configurable.rb index c466958..1903c73 100644 --- a/lib/rien/configurable.rb +++ b/lib/rien/configurable.rb @@ -1,51 +1,57 @@ -require 'tmpdir' +# frozen_string_literal: true -module Rien::Configurable - def self.included(base) - base.extend ClassMethods - end - - module ClassMethods - def config - @config ||= Configuration.new - end - - def configure - yield(config) +module Rien + module Configurable + def self.included(base) + base.extend ClassMethods end - end - class Configuration - attr_accessor :includes, :excludes, :output, :tmpdir, :silent + module ClassMethods + def config + @config ||= Configuration.new + end - def initialize - @includes = ["**/*"] # include all paths by default - @output = "rien_output" # final result - @tmpdir = File.expand_path("rien", Dir.tmpdir) # store intermediate results - @silent = false # see cli.rb wait_user_on_encoded + def configure + yield(config) + end end - def effective_paths - temp_paths = [] # store ruby files and directories - effective_paths = [] # only ruby files to be compiled - - @includes.each do |path| - path = "./#{path}" - temp_paths += Dir[path] + class Configuration + attr_accessor :includes, :excludes, + :output, :tmpdir, + :ruar, :ruar_key, :ruar_iv, :ruar_auth_data, + :silent + + def initialize + @includes = ['**/*'] # include all paths by default + @output = 'rien_output' # final result + @tmpdir = File.expand_path('rien', Dir.tmpdir) # store intermediate results + @silent = false + @ruar = false # see cli.rb wait_user_on_encoded end - unless excludes.nil? - @excludes.each do |path| + def effective_paths + temp_paths = [] # store ruby files and directories + effective_paths = [] # only ruby files to be compiled + + @includes.each do |path| path = "./#{path}" - temp_paths -= Dir[path] + temp_paths += Dir[path] end - end - temp_paths.each do |path| - effective_paths.push(path) unless File.directory?(path) || path.match("Rienfile") - end + unless excludes.nil? + @excludes.each do |path| + path = "./#{path}" + temp_paths -= Dir[path] + end + end + + temp_paths.each do |path| + effective_paths.push(path) unless File.directory?(path) || path.match('Rienfile') + end - effective_paths + effective_paths + end end end end diff --git a/lib/rien/const.rb b/lib/rien/const.rb index 45ca8db..0a788d2 100644 --- a/lib/rien/const.rb +++ b/lib/rien/const.rb @@ -1,12 +1,16 @@ -module Rien::Const - COMPILE_OPTION = { - inline_const_cache: true, - instructions_unification: true, - operands_unification: true, - peephole_optimization: true, - specialized_instruction: true, - stack_caching: true, - tailcall_optimization: true, - trace_instruction: false, - }.freeze +# frozen_string_literal: true + +module Rien + module Const + COMPILE_OPTION = { + inline_const_cache: true, + instructions_unification: true, + operands_unification: true, + peephole_optimization: true, + specialized_instruction: true, + stack_caching: true, + tailcall_optimization: true, + trace_instruction: false + }.freeze + end end diff --git a/lib/rien/core_ext/string.rb b/lib/rien/core_ext/string.rb index e2e924b..35cbd5d 100644 --- a/lib/rien/core_ext/string.rb +++ b/lib/rien/core_ext/string.rb @@ -1,5 +1,8 @@ +# frozen_string_literal: true + class String - def colorize(color_code) # ANSI color code + # ANSI color code + def colorize(color_code) "\e[#{color_code}m#{self}\e[0m" end diff --git a/lib/rien/decoder.rb b/lib/rien/decoder.rb index 56f1ab4..baafa97 100644 --- a/lib/rien/decoder.rb +++ b/lib/rien/decoder.rb @@ -1,19 +1,28 @@ -class Rien::Decoder - def self.check_version(version) - version == RUBY_VERSION - end +# frozen_string_literal: true + +module Rien + class Decoder + def self.check_version(version) + version == RUBY_VERSION + end + + def self.check_version!(version) + return if check_version(version) - def self.check_version!(version) - unless self.check_version(version) puts "Ruby Using: #{RUBY_VERSION}, Version Compiled: #{version}" exit(1) end - end - def self.eval(filename) - file = File.read(filename) - ir_bin = Zlib::Inflate.inflate(file) - ir = RubyVM::InstructionSequence.load_from_binary(ir_bin) - ir.eval + def self.eval(filename, mode: :plain) + file = case mode + when :ruar + Ruar.read(filename) + else + File.read(filename) + end + ir_bin = Zlib::Inflate.inflate(file) + ir = RubyVM::InstructionSequence.load_from_binary(ir_bin) + ir.eval + end end end diff --git a/lib/rien/encoder.rb b/lib/rien/encoder.rb index 8faa3be..9e34524 100644 --- a/lib/rien/encoder.rb +++ b/lib/rien/encoder.rb @@ -1,21 +1,32 @@ -class Rien::Encoder - def initialize(version=RUBY_VERSION) - @version = version - end +# frozen_string_literal: true - def encode_file(path) - # RubyVM::InstructionSequence.compile(source, __FILE__, relative_path, options) - bytecode = RubyVM::InstructionSequence.compile(File.read(path), path, path, options: Rien::Const::COMPILE_OPTION) - Zlib::Deflate.deflate(bytecode.to_binary) - end +module Rien + class Encoder + def initialize(version = RUBY_VERSION) + @version = version + end - def bootstrap - <<-EOL -require 'rien' + def encode_file(path) + # RubyVM::InstructionSequence.compile(source, __FILE__, relative_path, options) + bytecode = RubyVM::InstructionSequence.compile(File.read(path), path, path, options: Rien::Const::COMPILE_OPTION) + Zlib::Deflate.deflate(bytecode.to_binary) + end -Rien::Decoder.check_version!('#{RUBY_VERSION}') -Rien::Decoder.eval("\#{__FILE__}.rbc") - EOL + def bootstrap(mode: :plain) + case mode + when :ruar + <<~RUAR + # This file is compiled for Ruar + Rien::Decoder.check_version!('#{RUBY_VERSION}') + Rien::Decoder.eval("\#{__FILE__}.rbc", mode: :ruar) + RUAR + else + <<~PLAIN + require 'rien' + Rien::Decoder.check_version!('#{RUBY_VERSION}') + Rien::Decoder.eval("\#{__FILE__}.rbc") + PLAIN + end + end end - end diff --git a/lib/rien/error.rb b/lib/rien/error.rb new file mode 100644 index 0000000..9a6c0fc --- /dev/null +++ b/lib/rien/error.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +module Rien + module Error + class BassError < RuntimeError + attr_reader :path, :reason + + def initialize(operation, path, reason) + @path = path + @reason = reason + + super(+"failed to #{operation} -- #{path}, reason: #{reason}") + end + end + + class FailedToEncode < BassError + def initialize(path, reason) + super('encode', path, reason) + end + end + + class FailedToMove < BassError + def initialize(path, reason) + super('move', path, reason) + end + end + + class FailedToCopy < BassError + def initialize(path, reason) + super('copy', path, reason) + end + end + + class FailedToLoadRienfile < BassError + def initialize(path, reason) + super('load Rienfile', path, reason) + end + end + end +end diff --git a/lib/rien/version.rb b/lib/rien/version.rb index 61ffc32..559d911 100644 --- a/lib/rien/version.rb +++ b/lib/rien/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Rien - VERSION = '0.0.4' + VERSION = '0.0.5' end diff --git a/rien.gemspec b/rien.gemspec index 9926dd8..d15eca0 100644 --- a/rien.gemspec +++ b/rien.gemspec @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require './lib/rien/version' Gem::Specification.new do |s| @@ -7,7 +9,7 @@ Gem::Specification.new do |s| s.description = 'Encode your Ruby code for distribution' s.platform = Gem::Platform::RUBY - s.required_ruby_version = '>= 2.7.0' + s.required_ruby_version = '>= 3.0.0' s.license = 'Apache-2.0' @@ -25,8 +27,14 @@ Gem::Specification.new do |s| 'bug_tracker_uri' => 'https://github.com/coderemixer/rien/issues' } - s.add_runtime_dependency 'ruby-progressbar', '~> 1.9' - s.add_development_dependency 'rake', '~> 13.0.1' - s.add_development_dependency 'minitest', '~> 5.14.1' - s.add_development_dependency 'ci_reporter_minitest', '~> 1.0.0' + s.add_runtime_dependency 'ruar', '~> 0.0.4' + s.add_runtime_dependency 'ruby-progressbar', '~> 1.11.0' + + s.add_development_dependency 'minitest', '~> 5.14.3' + s.add_development_dependency 'minitest-reporters', '~> 1.4.3' + s.add_development_dependency 'rake', '~> 13.0.3' + s.add_development_dependency 'rake-compiler', '~> 1.1.1' + s.add_development_dependency 'rubocop', '~> 1.9.0' + s.add_development_dependency 'rubocop-minitest', '~> 0.10.3' + s.add_development_dependency 'rubocop-rake', '~>0.5.1' end diff --git a/test/unit/cli_helper_test.rb b/test/cli_helper_test.rb similarity index 96% rename from test/unit/cli_helper_test.rb rename to test/cli_helper_test.rb index 0a5b893..d1ed62a 100644 --- a/test/unit/cli_helper_test.rb +++ b/test/cli_helper_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class CliHelperTest < Minitest::Test @@ -21,7 +23,7 @@ def test_encode_single_plain def test_reject_not_ruby_file source = 'test/tmp/not_ruby.rb' - assert_raises(SystemExit){encode(source)} + assert_raises(Rien::Error::FailedToEncode) { encode(source) } end def test_export_single_encoded_plain @@ -113,5 +115,4 @@ def test_decode_autoload_gem assert_equal(expected, result) end - -end \ No newline at end of file +end diff --git a/test/unit/encoder_test.rb b/test/encoder_test.rb similarity index 83% rename from test/unit/encoder_test.rb rename to test/encoder_test.rb index 59d7295..83b14c0 100644 --- a/test/unit/encoder_test.rb +++ b/test/encoder_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class EncoderTest < Minitest::Test @@ -22,6 +24,6 @@ def test_encode_single_plain def test_reject_not_ruby_file source = 'test/tmp/not_ruby.rb' - assert_raises(Exception){encoder.encode_file(source)} + assert_raises(SyntaxError) { encoder.encode_file(source) } end -end \ No newline at end of file +end diff --git a/test/samples/autoload_gem.rb b/test/samples/autoload_gem.rb index fa60e5b..5dab42e 100644 --- a/test/samples/autoload_gem.rb +++ b/test/samples/autoload_gem.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + autoload(:Minitest, 'minitest') -puts "require gem minitest:#{Minitest::VERSION}" \ No newline at end of file +puts "require gem minitest:#{Minitest::VERSION}" diff --git a/test/samples/dir/ruby_in_dir.rb b/test/samples/dir/ruby_in_dir.rb index 66c6686..640d326 100644 --- a/test/samples/dir/ruby_in_dir.rb +++ b/test/samples/dir/ruby_in_dir.rb @@ -1 +1,3 @@ -puts "This is a ruby file in directory" \ No newline at end of file +# frozen_string_literal: true + +puts 'This is a ruby file in directory' diff --git a/test/samples/load_plain.rb b/test/samples/load_plain.rb index c76c531..4f67822 100644 --- a/test/samples/load_plain.rb +++ b/test/samples/load_plain.rb @@ -1 +1,3 @@ -load("test/samples/plain.rb") \ No newline at end of file +# frozen_string_literal: true + +load('test/samples/plain.rb') diff --git a/test/samples/not_ruby.rb b/test/samples/not_ruby.rb index cdbb76d..374cc1f 100644 --- a/test/samples/not_ruby.rb +++ b/test/samples/not_ruby.rb @@ -1 +1 @@ -This is not a ruby file! \ No newline at end of file +This is not a ruby file! diff --git a/test/samples/plain.rb b/test/samples/plain.rb index 42ae423..52f6674 100644 --- a/test/samples/plain.rb +++ b/test/samples/plain.rb @@ -1 +1,3 @@ -puts "This is a plain ruby file" +# frozen_string_literal: true + +puts 'This is a plain ruby file' diff --git a/test/samples/read_eval_plain.rb b/test/samples/read_eval_plain.rb index 3747d02..38bf996 100644 --- a/test/samples/read_eval_plain.rb +++ b/test/samples/read_eval_plain.rb @@ -1,2 +1,4 @@ -file = File.read("test/samples/plain.rb") -eval(file) \ No newline at end of file +# frozen_string_literal: true + +file = File.read('test/samples/plain.rb') +eval(file) diff --git a/test/samples/require_gem.rb b/test/samples/require_gem.rb index 42b37c5..7271f5f 100644 --- a/test/samples/require_gem.rb +++ b/test/samples/require_gem.rb @@ -1,2 +1,4 @@ -require "minitest" +# frozen_string_literal: true + +require 'minitest' puts "require gem minitest:#{Minitest::VERSION}" diff --git a/test/samples/require_relative_plain.rb b/test/samples/require_relative_plain.rb index c645b37..2462051 100644 --- a/test/samples/require_relative_plain.rb +++ b/test/samples/require_relative_plain.rb @@ -1 +1,3 @@ -require_relative './plain' \ No newline at end of file +# frozen_string_literal: true + +require_relative './plain' diff --git a/test/test_helper.rb b/test/test_helper.rb index 8bf8aab..be3422e 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,2 +1,9 @@ +# frozen_string_literal: true +# frozen_string_literal: true + +$LOAD_PATH.unshift File.expand_path('../lib', __dir__) + require 'minitest/autorun' -require 'rien' \ No newline at end of file +require 'minitest/reporters' +Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new] +require 'rien' From bdeae8f0561fc237e33f8c62b6ffdb3da1eeaea9 Mon Sep 17 00:00:00 2001 From: Kowalski Dark Date: Sat, 27 Feb 2021 02:40:45 +0800 Subject: [PATCH 2/3] Fix GitHub Actions --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 001a076..1176dbd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,4 +30,4 @@ jobs: gem install bundler bundle install --jobs 4 --retry 3 - name: Test - run: rake test + run: bundle exec rake test From 9969b8f51d5b5c08d066f595ec047d15dadf5c79 Mon Sep 17 00:00:00 2001 From: Kowalski Dark Date: Sat, 27 Feb 2021 02:56:54 +0800 Subject: [PATCH 3/3] Remove Rienfile in the final result --- .gitignore | 2 ++ lib/rien/cli/helper.rb | 1 + 2 files changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index ba5a729..1558a93 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ Gemfile.lock # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: .rvmrc dev*.rb +Rienfile +compiled* diff --git a/lib/rien/cli/helper.rb b/lib/rien/cli/helper.rb index b2266ac..1d99969 100644 --- a/lib/rien/cli/helper.rb +++ b/lib/rien/cli/helper.rb @@ -194,6 +194,7 @@ def use_rienfile_to_pack(source) pack_files(files, mode: :plain) end + FileUtils.rm './Rienfile' # under tmpdir msg = <<~MSG Successed to compile and pack #{source} into #{output} using #{rienfile}