git_toolbox 0.7.2 → 0.9.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.
@@ -17,60 +17,86 @@
17
17
 
18
18
  # frozen_string_literal: true
19
19
 
20
- require 'get/commons/common'
21
- require 'get/commons/git'
22
- require 'get/subcommand/command'
23
- require 'get/subcommand/license/license_retriever'
20
+ require_relative '../../commons/common'
21
+ require_relative '../../commons/git'
22
+ require_relative '../command'
23
+ require_relative './license_retriever'
24
24
 
25
25
  # Class length is disabled as most of its length is given by formatting.
26
26
  # rubocop:disable Metrics/ClassLength
27
27
  # Subcommand, it allow to choose a license.
28
28
  class License < Command
29
- def self.command
30
- @@command ||= new
31
- @@command
32
- end
33
-
34
- private_class_method :new
35
-
36
29
  private
37
30
 
38
31
  include Retriever
39
32
 
40
- @@command = nil
41
-
42
- @@usage = 'license -h|(<subcommand> [<subcommand-options])'
43
- @@description = 'Create a new LICENSE file with the chosen license. ' \
44
- 'Online licenses are retrieved from https://choosealicense.com/appendix/ . ' \
45
- 'Head there for more information about the licences.'
46
- @@subcommands = {}
47
- # This block is Optimist configuration. It is as long as the number of options of the command.
48
- # rubocop:disable Metrics/BlockLength
49
- @@option_parser = Optimist::Parser.new do
50
- subcommand_max_length = @@subcommands.keys.map { |k| k.to_s.length }.max
51
- subcommand_section = <<~SUBCOMMANDS unless @@subcommands.empty?
52
- Subcommands:
53
- #{@@subcommands.keys.map { |k| " #{k.to_s.ljust(subcommand_max_length)} => #{@@subcommands[k].description}" }.join("\n")}
54
- SUBCOMMANDS
55
- usage @@usage
56
- synopsis @@description + (subcommand_section.nil? ? '' : "\n") + subcommand_section.to_s
57
- opt :offline,
58
- 'Force the application to use the offline licenses.'
59
- opt :create_commit,
60
- 'Create a commit which adds the LICENSE file to the repository history.',
61
- short: :none
62
- opt :commit_type,
63
- 'Select the type of the commit. No effect if "--create-commit" is not given.',
64
- default: 'chore'
65
- educate_on_error
66
- stop_on @@subcommands.keys.map(&:to_s)
33
+ def initialize
34
+ super() do
35
+ @usage = 'license -h|(<subcommand> [<subcommand-options])'
36
+ @description = 'Create a new LICENSE file with the chosen license. ' \
37
+ 'Online licenses are retrieved from https://choosealicense.com/appendix/ . ' \
38
+ 'Head there for more information about the licences.'
39
+ @subcommands = {}
40
+ end
67
41
  end
68
- # rubocop:enable Metrics/BlockLength
69
42
 
70
- def initialize
71
- super(@@usage, @@description) do
72
- @options = Common.with_subcommand_exception_handling @@option_parser do
73
- @@option_parser.parse
43
+ def create_license_file
44
+ license_text = ask_for_license(@options[:offline])
45
+ File.write(File.expand_path(@filename), license_text)
46
+ puts 'License file created. You may need to modify it with the year and your name.'
47
+ end
48
+
49
+ def create_license_commit
50
+ CommandIssuer.run('git', 'stash', 'push', '--staged')
51
+
52
+ setup_at_exit_hook
53
+ CommandIssuer.run('git', 'add', "'#{@filename}'").then do |add_result|
54
+ if add_result.exit_status.zero?
55
+ CommandIssuer.run(
56
+ 'git',
57
+ 'commit',
58
+ '-m',
59
+ "'#{@options[:commit_type]}: add license file'"
60
+ ).then do |commit_result|
61
+ if commit_result.exit_status.positive?
62
+ Common.error 'Failed to create license commit'
63
+ else
64
+ puts 'License file committed.'
65
+ end
66
+ end
67
+ else
68
+ Common.error "Failed to add license file '#{@filename}' to stage."
69
+ end
70
+ end
71
+ end
72
+
73
+ protected
74
+
75
+ def setup_option_parser
76
+ @option_parser = Optimist::Parser.new(
77
+ @usage,
78
+ full_description,
79
+ stop_condition
80
+ ) do |usage_header, description, stop_condition|
81
+ usage usage_header
82
+ synopsis description
83
+ opt :offline,
84
+ 'Force the application to use the offline licenses.'
85
+ opt :create_commit,
86
+ 'Create a commit which adds the LICENSE file to the repository history.',
87
+ short: :none
88
+ opt :commit_type,
89
+ 'Select the type of the commit. No effect if "--create-commit" is not given.',
90
+ default: 'chore'
91
+ educate_on_error
92
+ stop_on stop_condition
93
+ end
94
+ end
95
+
96
+ def setup_action
97
+ @action = lambda do
98
+ @options = Common.with_subcommand_exception_handling @option_parser do
99
+ @option_parser.parse
74
100
  end
75
101
 
76
102
  @filename = 'LICENSE'
@@ -84,24 +110,20 @@ class License < Command
84
110
 
85
111
  create_license_commit
86
112
  end
113
+ rescue Interrupt
114
+ Common.print_then_do_and_exit "\nLicense creation cancelled"
87
115
  end
88
116
  end
89
117
 
90
- def create_license_file
91
- license_text = ask_for_license(@options[:offline])
92
- File.write(File.expand_path(@filename), license_text)
93
- puts 'License file created. You may need to modify it with the year and your name.'
94
- end
95
-
96
- def create_license_commit
97
- `git stash push --staged`
118
+ private
98
119
 
120
+ def setup_at_exit_hook
99
121
  # This block is given to at_exit to execute it in any case.
100
- at_exit { `[ "$(git stash list | wc -l)" -gt "0" ] && git stash pop > /dev/null` }
101
- `git add "#{@filename}" && git commit -m "chore: add license file"`
102
- Common.error 'Failed to create license commit' if $CHILD_STATUS.exitstatus.positive?
103
-
104
- puts 'License file committed.'
122
+ at_exit do
123
+ if CommandIssuer.run('git', 'stash', 'list').output.lines.length.positive?
124
+ CommandIssuer.run('git', 'stash', 'pop')
125
+ end
126
+ end
105
127
  end
106
128
  end
107
129
  # rubocop:enable Metrics/ClassLength
@@ -18,6 +18,7 @@
18
18
  # frozen_string_literal: true
19
19
 
20
20
  require 'highline'
21
+ require_relative '../../commons/http_client'
21
22
 
22
23
  # The retrieving module for licenses. It can gather licenses online (from https://choosealicense.com/appendix/)
23
24
  # or offline (from a predefined subset of licenses).
@@ -25,24 +26,25 @@ module Retriever
25
26
  BASE_OFFLINE_LICENSE_PATH = "#{File.dirname(File.expand_path(__FILE__))}/offline_licenses".freeze
26
27
  BASE_ONLINE_LICENSE_URI = 'https://choosealicense.com'
27
28
 
28
- @@cli = HighLine.new
29
+ Common.module_instance_value(self, 'cli', 'HighLine.new')
30
+ Common.add_module_self_reference(self)
29
31
 
30
32
  def ask_for_license(offline)
31
- @@offline = offline
32
- list = if @@offline
33
+ @offline = offline
34
+ list = if @offline
33
35
  offline_license_list
34
36
  else
35
37
  online_license_list
36
38
  end
37
39
 
38
- @@cli.puts 'Choose which license you want to use:'
39
- choice = @@cli.choose do |menu|
40
+ MOD_REF.cli.puts 'Choose which license you want to use:'
41
+ choice = MOD_REF.cli.choose do |menu|
40
42
  menu.flow = :column_down
41
43
  menu.prompt = ''
42
44
  list.each { |element| menu.choice(element) }
43
45
  end
44
46
 
45
- if @@offline
47
+ if @offline
46
48
  offline_license_text(choice)
47
49
  else
48
50
  online_license_text(choice)
@@ -56,18 +58,25 @@ module Retriever
56
58
  end
57
59
 
58
60
  def online_license_list
59
- @@online_licenses = {}
60
- text = `curl -fsL "#{BASE_ONLINE_LICENSE_URI}/appendix/" | grep '<th scope="row">'`.strip
61
- if $CHILD_STATUS.exitstatus.positive?
62
- puts 'WARNING: Unable to retrieve list of online licenses, falling back to offline ones.'
63
- @@offline = true
64
- offline_license_list
65
- else
66
- text.split("\n").each do |element|
61
+ @online_licenses = {}
62
+ response = HTTPClient.instance.http_get_request("#{BASE_ONLINE_LICENSE_URI}/appendix/")
63
+ if response.is_a?(Net::HTTPSuccess)
64
+ response.body
65
+ .strip
66
+ .lines
67
+ .select { |line| line.include?('<th scope="row">') }
68
+ .each do |element|
67
69
  match_result = element.match(%r{<a href="(.*)">(.*)</a>})
68
- @@online_licenses[match_result[2]] = match_result[1]
70
+ @online_licenses[match_result[2]] = match_result[1]
69
71
  end
70
- @@online_licenses.keys
72
+ @online_licenses.keys
73
+ else
74
+ warning_message = 'WARNING: Unable to retrieve list of online licenses ' \
75
+ "(cause: #{HTTPClient.instance.response_error_message(response)}), " \
76
+ 'falling back to offline ones.'
77
+ puts warning_message
78
+ @offline = true
79
+ offline_license_list
71
80
  end
72
81
  end
73
82
 
@@ -76,12 +85,18 @@ module Retriever
76
85
  end
77
86
 
78
87
  def online_license_text(license)
79
- page = `curl -fsL "#{BASE_ONLINE_LICENSE_URI}#{@@online_licenses[license]}"`
80
- Common.error 'Failed to retrieve the license text.' if $CHILD_STATUS.exitstatus.positive?
81
-
82
- match_result = page.match(%r{<pre id="license-text">(.*)</pre>}m)
83
- Common.error 'Invalid license text' if match_result[1].nil?
84
-
85
- match_result[1]
88
+ response = HTTPClient.instance.http_get_request("#{BASE_ONLINE_LICENSE_URI}#{@online_licenses[license]}")
89
+ if response.is_a?(Net::HTTPSuccess)
90
+ match_result = response.body.match(%r{<pre id="license-text">(.*)</pre>}m)
91
+ if match_result[1].nil?
92
+ Common.error 'Invalid license text'
93
+ else
94
+ match_result[1]
95
+ end
96
+ else
97
+ error_message = 'Failed to retrieve the license text ' \
98
+ "(cause: #{HTTPClient.instance.response_error_message(response)})."
99
+ Common.error error_message
100
+ end
86
101
  end
87
102
  end
@@ -17,64 +17,44 @@
17
17
 
18
18
  # frozen_string_literal: true
19
19
 
20
- require 'English'
21
- require 'get/commons/common'
22
- require 'get/commons/git'
23
- require 'get/subcommand/command'
20
+ require_relative '../../commons/common'
21
+ require_relative '../../commons/git'
22
+ require_relative '../command'
24
23
 
25
24
  # Class length is disabled as most of its length is given by formatting.
26
25
  # rubocop:disable Metrics/ClassLength
27
26
  # Subcommand, it allow to create a new repository and add an initial, empty commit to it.
28
27
  class Tree < Command
29
- def self.command
30
- @@command ||= new
31
- @@command
32
- end
33
-
34
- private_class_method :new
35
-
36
28
  private
37
29
 
38
- @@command = nil
39
-
40
- @@usage = 'tree -h|(<subcommand> [<subcommand-options])'
41
- @@description = 'Print the tree of commits.'
42
- @@subcommands = {}
43
- # This block is Optimist configuration. It is as long as the number of options of the command.
44
- # rubocop:disable Metrics/BlockLength
45
- @@option_parser = Optimist::Parser.new do
46
- subcommand_max_length = @@subcommands.keys.map { |k| k.to_s.length }.max
47
- subcommand_section = <<~SUBCOMMANDS unless @@subcommands.empty?
48
- Subcommands:
49
- #{@@subcommands.keys.map { |k| " #{k.to_s.ljust(subcommand_max_length)} => #{@@subcommands[k].description}" }.join("\n")}
50
- SUBCOMMANDS
51
- usage @@usage
52
- synopsis @@description + (subcommand_section.nil? ? '' : "\n") + subcommand_section.to_s
53
- educate_on_error
54
- stop_on @@subcommands.keys.map(&:to_s)
55
- end
56
- # rubocop:enable Metrics/BlockLength
57
-
58
30
  def initialize
59
- super(@@usage, @@description) do
60
- @options = Common.with_subcommand_exception_handling @@option_parser do
61
- @@option_parser.parse
62
- end
63
- Common.error 'tree need to be run inside a git repository' unless Git.in_repo?
64
-
65
- view_tree
31
+ super() do
32
+ @usage = 'tree -h|(<subcommand> [<subcommand-options])'
33
+ @description = 'Print the tree of commits. ' \
34
+ 'If the output is redirected to a pager (i.e. \'less\'), ' \
35
+ 'you may need to enable the parsing of escape sequences.'
36
+ @subcommands = {}
66
37
  end
67
38
  end
68
39
 
69
40
  def view_tree
70
- page_log(transform_log(log))
41
+ puts transform_log(log)
71
42
  end
72
43
 
73
44
  TREE_FORMAT = '%C(bold blue)%h%C(reset)§%C(dim normal)(%cr)%C(reset)§%C(auto)%d%C(reset)§§%n' \
74
45
  '§§§ %C(normal)%an%C(reset)%C(dim normal): %s%C(reset)'
75
46
 
76
47
  def log
77
- `git log --all --graph --decorate=short --date-order --color --pretty=format:"#{TREE_FORMAT}"`
48
+ CommandIssuer.run(
49
+ 'git',
50
+ 'log',
51
+ '--all',
52
+ '--graph',
53
+ '--decorate=short',
54
+ '--date-order',
55
+ '--color',
56
+ "--pretty=format:\"#{TREE_FORMAT}\""
57
+ ).output
78
58
  end
79
59
 
80
60
  TIME_REGEX = /(\([a-z0-9 ,]+\))/
@@ -90,21 +70,18 @@ class Tree < Command
90
70
  # calc color escape codes length
91
71
  time_color_length = first_line_time.length - first_line_time.match(TIME_REGEX)[1].length
92
72
 
93
- # calc max length of time references
94
- time_padding = 0
95
- split_lines.each { |element| time_padding = [time_padding, element[1].length - time_color_length].max }
73
+ time_padding = global_fitting_time_padding(split_lines, time_color_length)
96
74
 
97
- # format strings
98
75
  split_lines
99
76
  .map do |element|
100
77
  # Only lines with the date reference have the color escape codes,
101
78
  # the other lines do not need the additional padding
102
79
  left_padding = TIME_MINIMUM_PADDING + time_padding +
103
- (element[1].match?(TIME_REGEX) ? time_color_length : 0)
80
+ (!element[1].nil? && element[1].match?(TIME_REGEX) ? time_color_length : 0)
104
81
  format(
105
82
  '%<date>s %<tree_mark>s %<pointers>s %<commit_text>s',
106
83
  {
107
- date: element[1].rjust(left_padding),
84
+ date: (element[1].nil? ? '' : element[1]).rjust(left_padding),
108
85
  tree_mark: element[0],
109
86
  pointers: element[2],
110
87
  commit_text: element[3]
@@ -115,8 +92,40 @@ class Tree < Command
115
92
  end
116
93
  # rubocop:enable Metrics/MethodLength
117
94
 
118
- def page_log(text)
119
- system("less -RfS <(echo -e '#{text}')")
95
+ def global_fitting_time_padding(lines, time_color_length)
96
+ time_padding = 0
97
+ lines
98
+ # If element[1].nil? then the line refers to a intersection between branch lines
99
+ # they do not have a time reference
100
+ .reject { |element| element[1].nil? }
101
+ .each { |element| time_padding = [time_padding, element[1].length - time_color_length].max }
102
+ time_padding
103
+ end
104
+
105
+ protected
106
+
107
+ def setup_option_parser
108
+ @option_parser = Optimist::Parser.new(
109
+ @usage,
110
+ full_description,
111
+ stop_condition
112
+ ) do |usage_header, description, stop_condition|
113
+ usage usage_header
114
+ synopsis description
115
+ educate_on_error
116
+ stop_on stop_condition
117
+ end
118
+ end
119
+
120
+ def setup_action
121
+ @action = lambda do
122
+ @options = Common.with_subcommand_exception_handling @option_parser do
123
+ @option_parser.parse
124
+ end
125
+ Common.error 'tree need to be run inside a git repository' unless Git.in_repo?
126
+
127
+ view_tree
128
+ end
120
129
  end
121
130
  end
122
131
  # rubocop:enable Metrics/ClassLength
data/lib/get/version.rb CHANGED
@@ -17,6 +17,4 @@
17
17
 
18
18
  # frozen_string_literal: true
19
19
 
20
- module Get
21
- VERSION = '0.7.2'
22
- end
20
+ GET_VERSION = '0.9.0'
data/lib/get.rb CHANGED
@@ -28,48 +28,61 @@ require 'get/subcommand/changelog/changelog'
28
28
  require 'get/subcommand/tree/tree'
29
29
  require 'get/version'
30
30
  require 'get/commons/common'
31
+ require 'get/subcommand/command'
31
32
 
32
- # Entrypoint of Get
33
- module Get
33
+ # Main command of Get.
34
+ class Get < Command
34
35
  class Error < StandardError; end
35
36
 
36
- @@subcommands = {
37
- describe: Describe.command,
38
- commit: Commit.command,
39
- init: Init.command,
40
- license: License.command,
41
- complete: Complete.command,
42
- changelog: Changelog.command,
43
- tree: Tree.command,
44
- }
45
- @@option_parser = Optimist::Parser.new do
46
- subcommand_max_length = @@subcommands.keys.map { |k| k.to_s.length }.max
47
- usage '-h|-v|(<subcommand> [<subcommand-options])'
48
- synopsis <<~SUBCOMMANDS unless @@subcommands.empty?
49
- Subcommands:
50
- #{@@subcommands.keys.map { |k| " #{k.to_s.ljust(subcommand_max_length)} => #{@@subcommands[k].description}" }.join("\n")}
51
- SUBCOMMANDS
52
- version "Get version: #{Get::VERSION}"
53
- educate_on_error
54
- stop_on @@subcommands.keys.map(&:to_s)
37
+ def initialize
38
+ super() do
39
+ @usage = '-h|-v|(<subcommand> [<subcommand-options])'
40
+ @description = ''
41
+ @subcommands = {
42
+ describe: Describe.instance,
43
+ commit: Commit.instance,
44
+ init: Init.instance,
45
+ license: License.instance,
46
+ complete: Complete.instance,
47
+ changelog: Changelog.instance,
48
+ tree: Tree.instance,
49
+ }
50
+ end
55
51
  end
56
52
 
57
- def self.main
58
- @options = Optimist.with_standard_exception_handling(@@option_parser) do
59
- @@option_parser.parse
60
- end
61
- error 'No command or option specified' if ARGV.empty?
62
- command = ARGV.shift.to_sym
63
- if @@subcommands.include?(command)
64
- @@subcommands[command].action.call
65
- else
66
- error "Unknown subcommand '#{command}'"
53
+ def main
54
+ @action.call
55
+ end
56
+
57
+ protected
58
+
59
+ def setup_option_parser
60
+ @option_parser = Optimist::Parser.new(
61
+ @usage,
62
+ full_description,
63
+ GET_VERSION,
64
+ stop_condition
65
+ ) do |usage_header, description, version, stop_condition|
66
+ usage usage_header
67
+ synopsis description
68
+ version "Get version: #{version}"
69
+ educate_on_error
70
+ stop_on stop_condition
67
71
  end
68
72
  end
69
73
 
70
- def self.error(message)
71
- Common.error message do
72
- @@option_parser.educate
74
+ def setup_action
75
+ @action = lambda do
76
+ @options = Optimist.with_standard_exception_handling(@option_parser) do
77
+ @option_parser.parse
78
+ end
79
+ educated_error 'No command or option specified' if ARGV.empty?
80
+ command = ARGV.shift.to_sym
81
+ if @subcommands.include?(command)
82
+ @subcommands[command].action.call
83
+ else
84
+ educated_error "Unknown subcommand '#{command}'"
85
+ end
73
86
  end
74
87
  end
75
88
  end
metadata CHANGED
@@ -1,49 +1,49 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git_toolbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Speranza
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-02 00:00:00.000000000 Z
11
+ date: 2023-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: optimist
14
+ name: highline
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '3.0'
20
- - - ">="
21
- - !ruby/object:Gem::Version
22
- version: 3.0.1
19
+ version: 2.0.3
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - "~>"
28
25
  - !ruby/object:Gem::Version
29
- version: '3.0'
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: 3.0.1
26
+ version: 2.0.3
33
27
  - !ruby/object:Gem::Dependency
34
- name: highline
28
+ name: optimist
35
29
  requirement: !ruby/object:Gem::Requirement
36
30
  requirements:
37
31
  - - "~>"
38
32
  - !ruby/object:Gem::Version
39
- version: 2.0.3
33
+ version: '3.0'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 3.0.1
40
37
  type: :runtime
41
38
  prerelease: false
42
39
  version_requirements: !ruby/object:Gem::Requirement
43
40
  requirements:
44
41
  - - "~>"
45
42
  - !ruby/object:Gem::Version
46
- version: 2.0.3
43
+ version: '3.0'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 3.0.1
47
47
  description:
48
48
  email:
49
49
  - alex.speranza@studio.unibo.it
@@ -55,8 +55,10 @@ files:
55
55
  - bin/get
56
56
  - bin/setup
57
57
  - lib/get.rb
58
+ - lib/get/commons/command_issuer.rb
58
59
  - lib/get/commons/common.rb
59
60
  - lib/get/commons/git.rb
61
+ - lib/get/commons/http_client.rb
60
62
  - lib/get/subcommand/changelog/changelog.rb
61
63
  - lib/get/subcommand/command.rb
62
64
  - lib/get/subcommand/commit/commit.rb
@@ -94,7 +96,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
94
96
  requirements:
95
97
  - - ">="
96
98
  - !ruby/object:Gem::Version
97
- version: 3.1.0
99
+ version: 3.0.0
98
100
  required_rubygems_version: !ruby/object:Gem::Requirement
99
101
  requirements:
100
102
  - - ">="