makit 0.0.48 → 0.0.49

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generated/makit/v1/makit.v1_pb.rb +34 -0
  3. data/lib/generated/makit/v1/web/link_pb.rb +20 -0
  4. data/lib/makit/apache.rb +32 -32
  5. data/lib/makit/cli/clean.rb +14 -14
  6. data/lib/makit/cli/clone.rb +59 -59
  7. data/lib/makit/cli/init.rb +38 -38
  8. data/lib/makit/cli/main.rb +33 -33
  9. data/lib/makit/cli/make.rb +54 -54
  10. data/lib/makit/cli/new.rb +37 -37
  11. data/lib/makit/cli/nuget_cache.rb +38 -38
  12. data/lib/makit/cli/pull.rb +31 -31
  13. data/lib/makit/cli/setup.rb +71 -71
  14. data/lib/makit/cli/work.rb +21 -21
  15. data/lib/makit/command_runner.rb +399 -391
  16. data/lib/makit/commands.rb +21 -21
  17. data/lib/makit/content/default_gitignore.rb +5 -5
  18. data/lib/makit/content/default_rakefile.rb +11 -11
  19. data/lib/makit/content/gem_rakefile.rb +14 -14
  20. data/lib/makit/data.rb +50 -50
  21. data/lib/makit/directories.rb +140 -140
  22. data/lib/makit/directory.rb +200 -200
  23. data/lib/makit/dotnet.rb +170 -162
  24. data/lib/makit/environment.rb +127 -127
  25. data/lib/makit/fileinfo.rb +16 -16
  26. data/lib/makit/files.rb +47 -47
  27. data/lib/makit/git.rb +87 -87
  28. data/lib/makit/gitlab_runner.rb +60 -60
  29. data/lib/makit/humanize.rb +129 -129
  30. data/lib/makit/indexer.rb +56 -56
  31. data/lib/makit/logging.rb +96 -96
  32. data/lib/makit/markdown.rb +75 -75
  33. data/lib/makit/mp/basic_object_mp.rb +16 -16
  34. data/lib/makit/mp/command_request.mp.rb +16 -16
  35. data/lib/makit/mp/project_mp.rb +210 -210
  36. data/lib/makit/mp/string_mp.rb +137 -122
  37. data/lib/makit/nuget.rb +57 -57
  38. data/lib/makit/protoc.rb +104 -104
  39. data/lib/makit/serializer.rb +115 -115
  40. data/lib/makit/show.rb +106 -108
  41. data/lib/makit/storage.rb +131 -131
  42. data/lib/makit/symbols.rb +149 -149
  43. data/lib/makit/tasks.rb +61 -60
  44. data/lib/makit/tree.rb +37 -37
  45. data/lib/makit/v1/makit.v1_pb.rb +33 -34
  46. data/lib/makit/v1/makit.v1_services_pb.rb +25 -25
  47. data/lib/makit/version.rb +52 -52
  48. data/lib/makit/wix.rb +95 -95
  49. data/lib/makit/zip.rb +17 -17
  50. data/lib/makit.rb +267 -267
  51. metadata +4 -2
data/lib/makit/files.rb CHANGED
@@ -1,47 +1,47 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "directory"
4
- require_relative "environment"
5
- require_relative "protoc"
6
- require_relative "nuget"
7
- require_relative "version"
8
- require "rake"
9
-
10
- # This module provides classes for the Makit gem.
11
- module Makit
12
- # This class provide methods for working with the system Environment.
13
- #
14
- module Files
15
- if (Makit::Directories::PROJECT_ROOT != nil)
16
- Dir.chdir(Makit::Directories::PROJECT_ROOT) do
17
- CSPROJ = Dir.glob("**/*.csproj")
18
- end
19
- else
20
- CSPROJ = Array.new
21
- end
22
-
23
- # show all the files constants in a nicely formatted table format with the name of the constant and the value
24
- def self.show
25
- # Array of constant names (symbols)
26
- constant_names = [:CSPROJ]
27
-
28
- # Find the length of the longest constant name and add 1
29
- max_length = constant_names.map(&:to_s).max_by(&:length).length + 1
30
-
31
- # Iterate through each constant name
32
- constant_names.each do |constant_name|
33
- begin
34
- constant_value = const_get(constant_name) # Fetch the value of the constant
35
- if (constant_value != nil && File.exist?(constant_value))
36
- constant_value = constant_value.colorize(:green)
37
- end
38
- # Print the constant name right justified to the max_length
39
- puts "#{constant_name.to_s.rjust(max_length)} = #{constant_value}"
40
- rescue NameError
41
- # Handle the case where the constant is not defined
42
- puts "#{constant_name.to_s.rjust(max_length)} = [Constant not defined]"
43
- end
44
- end
45
- end
46
- end # module Files
47
- end # module Makit
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "directory"
4
+ require_relative "environment"
5
+ require_relative "protoc"
6
+ require_relative "nuget"
7
+ require_relative "version"
8
+ require "rake"
9
+
10
+ # This module provides classes for the Makit gem.
11
+ module Makit
12
+ # This class provide methods for working with the system Environment.
13
+ #
14
+ module Files
15
+ if (Makit::Directories::PROJECT_ROOT != nil)
16
+ Dir.chdir(Makit::Directories::PROJECT_ROOT) do
17
+ CSPROJ = Dir.glob("**/*.csproj")
18
+ end
19
+ else
20
+ CSPROJ = Array.new
21
+ end
22
+
23
+ # show all the files constants in a nicely formatted table format with the name of the constant and the value
24
+ def self.show
25
+ # Array of constant names (symbols)
26
+ constant_names = [:CSPROJ]
27
+
28
+ # Find the length of the longest constant name and add 1
29
+ max_length = constant_names.map(&:to_s).max_by(&:length).length + 1
30
+
31
+ # Iterate through each constant name
32
+ constant_names.each do |constant_name|
33
+ begin
34
+ constant_value = const_get(constant_name) # Fetch the value of the constant
35
+ if (constant_value != nil && File.exist?(constant_value))
36
+ constant_value = constant_value.colorize(:green)
37
+ end
38
+ # Print the constant name right justified to the max_length
39
+ puts "#{constant_name.to_s.rjust(max_length)} = #{constant_value}"
40
+ rescue NameError
41
+ # Handle the case where the constant is not defined
42
+ puts "#{constant_name.to_s.rjust(max_length)} = [Constant not defined]"
43
+ end
44
+ end
45
+ end
46
+ end # module Files
47
+ end # module Makit
data/lib/makit/git.rb CHANGED
@@ -1,87 +1,87 @@
1
- # frozen_string_literal: true
2
-
3
- # This module provides classes for the Makit gem.
4
- module Makit
5
- # This class provide methods for working with the system Environment.
6
- #
7
- class Git
8
- def self.is_git_repo
9
- Dir.exist? ".git"
10
- end
11
-
12
- def self.detached
13
- `git status`.include?("detached")
14
- end
15
-
16
- def self.is_read_only
17
- !is_git_repo || detached
18
- end
19
-
20
- def self.is_clean
21
- `git status --porcelain`.empty?
22
- end
23
-
24
- def self.integrate
25
- if is_git_repo && !detached
26
- "git add .".run
27
- "git commit -m \"integrate\"".run unless is_clean
28
- end
29
- end
30
-
31
- def self.sync
32
- if is_git_repo && !detached
33
- "git pull".try
34
- "git push origin".try
35
- "git push origin --tags".try
36
- end
37
- end
38
-
39
- def self.pull
40
- if is_git_repo && !detached
41
- "git pull".try
42
- end
43
- end
44
-
45
- def self.zip_source_files(zipfilename)
46
- "git archive --format zip --output #{zipfilename} HEAD".run
47
- end
48
-
49
- def self.get_file_infos()
50
- file_infos = []
51
- command = `git ls-files`
52
- command.split("\n").map do |path|
53
- begin
54
- file_infos << FileInfo.new(name: path, mtime: File.mtime(path), size: File.size(path))
55
- rescue
56
- next
57
- end
58
- end
59
- file_infos.sort_by! { |info| info.mtime }.reverse!
60
- file_infos
61
- end
62
-
63
- def self.branch
64
- `git branch --show-current`.strip
65
- end
66
-
67
- def self.commitsha
68
- `git rev-parse HEAD`.strip
69
- end
70
-
71
- def self.commitmsg
72
- `git log -1 --pretty=%B`.strip
73
- end
74
-
75
- def self.commitdate
76
- `git log -1 --pretty=%cd`.strip
77
- end
78
-
79
- def self.commitauthor
80
- `git log -1 --pretty=%an`.strip
81
- end
82
-
83
- def self.commitemail
84
- `git log -1 --pretty=%ae`.strip
85
- end
86
- end
87
- end
1
+ # frozen_string_literal: true
2
+
3
+ # This module provides classes for the Makit gem.
4
+ module Makit
5
+ # This class provide methods for working with the system Environment.
6
+ #
7
+ class Git
8
+ def self.is_git_repo
9
+ Dir.exist? ".git"
10
+ end
11
+
12
+ def self.detached
13
+ `git status`.include?("detached")
14
+ end
15
+
16
+ def self.is_read_only
17
+ !is_git_repo || detached
18
+ end
19
+
20
+ def self.is_clean
21
+ `git status --porcelain`.empty?
22
+ end
23
+
24
+ def self.integrate
25
+ if is_git_repo && !detached
26
+ "git add .".run
27
+ "git commit -m \"integrate\"".run unless is_clean
28
+ end
29
+ end
30
+
31
+ def self.sync
32
+ if is_git_repo && !detached
33
+ "git pull".try
34
+ "git push origin".try
35
+ "git push origin --tags".try
36
+ end
37
+ end
38
+
39
+ def self.pull
40
+ if is_git_repo && !detached
41
+ "git pull".try
42
+ end
43
+ end
44
+
45
+ def self.zip_source_files(zipfilename)
46
+ "git archive --format zip --output #{zipfilename} HEAD".run
47
+ end
48
+
49
+ def self.get_file_infos()
50
+ file_infos = []
51
+ command = `git ls-files`
52
+ command.split("\n").map do |path|
53
+ begin
54
+ file_infos << FileInfo.new(name: path, mtime: File.mtime(path), size: File.size(path))
55
+ rescue
56
+ next
57
+ end
58
+ end
59
+ file_infos.sort_by! { |info| info.mtime }.reverse!
60
+ file_infos
61
+ end
62
+
63
+ def self.branch
64
+ `git branch --show-current`.strip
65
+ end
66
+
67
+ def self.commitsha
68
+ `git rev-parse HEAD`.strip
69
+ end
70
+
71
+ def self.commitmsg
72
+ `git log -1 --pretty=%B`.strip
73
+ end
74
+
75
+ def self.commitdate
76
+ `git log -1 --pretty=%cd`.strip
77
+ end
78
+
79
+ def self.commitauthor
80
+ `git log -1 --pretty=%an`.strip
81
+ end
82
+
83
+ def self.commitemail
84
+ `git log -1 --pretty=%ae`.strip
85
+ end
86
+ end
87
+ end
@@ -1,60 +1,60 @@
1
- # frozen_string_literal: true
2
-
3
- require "yaml"
4
- require "fileutils"
5
-
6
- # This module provides classes for the Makit gem.
7
- module Makit
8
- # This class provide methods for working with Directories/
9
- #
10
- # Example:
11
- #
12
- # Makit::Directory.find_directory_with_pattern("/home/user", "*.rb")
13
- #
14
- class GitLabRunner
15
-
16
- # Parse the .gitlab-ci.yml file
17
- def parse_gitlab_ci_file(file_path)
18
- YAML.load_file(file_path)
19
- end
20
-
21
- # Extract the script for a specified job
22
- def extract_script(ci_config, job_name)
23
- job = ci_config[job_name]
24
- job ? job["script"] : nil
25
- end
26
-
27
- # Write the script to a temporary file
28
- def write_script_to_file(script, file_path)
29
- File.open(file_path, "w") do |file|
30
- script.each { |line| file.puts(line) }
31
- end
32
- end
33
-
34
- # Run the script in a Docker container
35
- def run_script_in_docker(image, script_file)
36
- system("docker run --rm -v #{Dir.pwd}:/workspace -w /workspace #{image} /bin/sh #{script_file}")
37
- end
38
-
39
- # Main function to execute the process
40
- def run_job(ci_file_path, job_name, docker_image)
41
- ci_config = parse_gitlab_ci_file(ci_file_path)
42
- script = extract_script(ci_config, job_name)
43
-
44
- unless script
45
- puts "Job '#{job_name}' not found in #{ci_file_path}"
46
- return
47
- end
48
-
49
- script_file = "temp_script.sh"
50
- write_script_to_file(script, script_file)
51
- FileUtils.chmod("+x", script_file)
52
-
53
- puts "Running script in Docker container..."
54
- run_script_in_docker(docker_image, script_file)
55
-
56
- # Clean up the temporary script file
57
- FileUtils.rm(script_file)
58
- end
59
- end
60
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "fileutils"
5
+
6
+ # This module provides classes for the Makit gem.
7
+ module Makit
8
+ # This class provide methods for working with Directories/
9
+ #
10
+ # Example:
11
+ #
12
+ # Makit::Directory.find_directory_with_pattern("/home/user", "*.rb")
13
+ #
14
+ class GitLabRunner
15
+
16
+ # Parse the .gitlab-ci.yml file
17
+ def parse_gitlab_ci_file(file_path)
18
+ YAML.load_file(file_path)
19
+ end
20
+
21
+ # Extract the script for a specified job
22
+ def extract_script(ci_config, job_name)
23
+ job = ci_config[job_name]
24
+ job ? job["script"] : nil
25
+ end
26
+
27
+ # Write the script to a temporary file
28
+ def write_script_to_file(script, file_path)
29
+ File.open(file_path, "w") do |file|
30
+ script.each { |line| file.puts(line) }
31
+ end
32
+ end
33
+
34
+ # Run the script in a Docker container
35
+ def run_script_in_docker(image, script_file)
36
+ system("docker run --rm -v #{Dir.pwd}:/workspace -w /workspace #{image} /bin/sh #{script_file}")
37
+ end
38
+
39
+ # Main function to execute the process
40
+ def run_job(ci_file_path, job_name, docker_image)
41
+ ci_config = parse_gitlab_ci_file(ci_file_path)
42
+ script = extract_script(ci_config, job_name)
43
+
44
+ unless script
45
+ puts "Job '#{job_name}' not found in #{ci_file_path}"
46
+ return
47
+ end
48
+
49
+ script_file = "temp_script.sh"
50
+ write_script_to_file(script, script_file)
51
+ FileUtils.chmod("+x", script_file)
52
+
53
+ puts "Running script in Docker container..."
54
+ run_script_in_docker(docker_image, script_file)
55
+
56
+ # Clean up the temporary script file
57
+ FileUtils.rm(script_file)
58
+ end
59
+ end
60
+ end
@@ -1,129 +1,129 @@
1
- # frozen_string_literal: true
2
-
3
- # This module provides classes for the Makit gem.
4
- module Makit
5
- class Humanize
6
- def self.get_humanized_size(bytes, precision = 2)
7
- units = ["B", "KB", "MB", "GB", "TB", "PB"]
8
- return "0 B" if bytes == 0
9
-
10
- exp = (Math.log(bytes) / Math.log(1024)).to_i
11
- exp = units.size - 1 if exp >= units.size
12
-
13
- size = bytes.to_f / (1024 ** exp)
14
- format("%.#{precision}f %s", size, units[exp])
15
- end
16
-
17
- def self.get_humanized_timestamp(timestamp)
18
- return timestamp.strftime("%Y-%m-%d %I:%M:%S %p") if timestamp.respond_to?(:strftime)
19
- timestamp.strftime("%Y-%m-%d %H:%M:%S")
20
- end
21
-
22
- def self.get_make_result_summary(make_result)
23
- summary = "Make Result\n"
24
- summary += " Repository: #{make_result.repository}\n"
25
- summary += " Commit: #{make_result.commit}\n"
26
- summary += " Branch: #{make_result.branch}\n"
27
- summary += " Tag: #{make_result.tag}\n"
28
- summary += " Device: #{make_result.device}\n"
29
- summary += " Runtime Identifier: #{make_result.runtime_identifier}\n"
30
- summary += " Initial Size: #{get_humanized_size(make_result.initial_size)}\n"
31
- summary += " Final Size: #{get_humanized_size(make_result.final_size)}\n"
32
- summary += " Delta Size: #{get_humanized_size(make_result.final_size - make_result.initial_size)}\n"
33
- summary += " Commands: (#{make_result.commands.length})\n"
34
- make_result.commands.each do |command|
35
- details = get_command_details(command)
36
- summary += "\n"
37
- summary += indent_string(details, 4)
38
- summary += "\n"
39
- end
40
-
41
- summary
42
- end
43
-
44
- def self.get_commands(commands)
45
- message = ""
46
- commands.each do |command|
47
- message += Makit::Humanize::get_command_details(command)
48
- end
49
- message
50
- end
51
-
52
- def self.get_command_summary(command)
53
- symbol = Makit::Symbols.warning
54
- symbol = Makit::Symbols.checkmark if !command.exit_code.nil? && command.exit_code.zero?
55
- symbol = Makit::Symbols.error if command.exit_code != 0
56
- "#{symbol} #{command.name} #{command.arguments.join(" ")}"
57
- end
58
-
59
- def self.get_command_details(command)
60
- summary = "#{get_command_summary(command)}\n"
61
- summary += " Name: #{command.name}\n"
62
- summary += " Arguments: #{command.arguments.join(" ")}\n"
63
- summary += " Directory: #{command.directory}\n"
64
- summary += " Exit Code: #{command.exit_code}\n"
65
- if command.output.length > 0
66
- summary += " Output:\n"
67
- summary += indent_string(command.output, 4)
68
- summary += "\n"
69
- end
70
- if command.error.length > 0
71
- summary += " Error:\n"
72
- summary += indent_string(command.error, 4)
73
- summary += "\n"
74
- end
75
- summary
76
- end
77
-
78
- def self.indent_string(string, spaces)
79
- string.split("\n").map { |line| " " * spaces + line }.join("\n")
80
- end
81
-
82
- def self.get_protobuf_timestamp(timestamp)
83
- Time.at(timestamp.seconds, timestamp.nanos / 1000.0).strftime("%Y-%m-%d %H:%M:%S")
84
- end
85
-
86
- def self.get_protobuf_duration(duration)
87
- total_seconds = duration.seconds + (duration.nanos / 1_000_000_000.0)
88
- hours = (total_seconds / 3600).to_i
89
- minutes = ((total_seconds % 3600) / 60).to_i
90
- seconds = (total_seconds % 60).round(2)
91
- "#{hours}h #{minutes}m #{seconds}s"
92
- end
93
-
94
- def self.get_humanized_duration(seconds_value)
95
- minutes = (seconds_value / 60).to_i
96
- seconds = (seconds_value % 60).to_i
97
- hours = (minutes / 60).to_i
98
- minutes = minutes % 60
99
- days = (hours / 24).to_i
100
- hours = hours % 24
101
- milliseconds = (seconds_value % 1 * 1000).to_i
102
-
103
- parts = []
104
- parts << "#{days} days" if days > 0
105
- parts << "#{hours} hours" if hours > 0
106
- if(minutes > 0)
107
- if(minutes == 1)
108
- parts << "1 minute"
109
- else
110
- parts << "#{minutes} minutes"
111
- end
112
- end
113
- if(seconds > 0)
114
- if(seconds == 1)
115
- parts << "1 second"
116
- else
117
- parts << "#{seconds} seconds"
118
- end
119
- end
120
- #parts << "#{seconds} seconds" if seconds > 0
121
- parts << "#{milliseconds} milliseconds" if milliseconds > 0 && seconds < 1
122
-
123
- if(parts.length == 0)
124
- parts << "0 seconds"
125
- end
126
- parts.join(", ")
127
- end
128
- end
129
- end
1
+ # frozen_string_literal: true
2
+
3
+ # This module provides classes for the Makit gem.
4
+ module Makit
5
+ class Humanize
6
+ def self.get_humanized_size(bytes, precision = 2)
7
+ units = ["B", "KB", "MB", "GB", "TB", "PB"]
8
+ return "0 B" if bytes == 0
9
+
10
+ exp = (Math.log(bytes) / Math.log(1024)).to_i
11
+ exp = units.size - 1 if exp >= units.size
12
+
13
+ size = bytes.to_f / (1024 ** exp)
14
+ format("%.#{precision}f %s", size, units[exp])
15
+ end
16
+
17
+ def self.get_humanized_timestamp(timestamp)
18
+ return timestamp.strftime("%Y-%m-%d %I:%M:%S %p") if timestamp.respond_to?(:strftime)
19
+ timestamp.strftime("%Y-%m-%d %H:%M:%S")
20
+ end
21
+
22
+ def self.get_make_result_summary(make_result)
23
+ summary = "Make Result\n"
24
+ summary += " Repository: #{make_result.repository}\n"
25
+ summary += " Commit: #{make_result.commit}\n"
26
+ summary += " Branch: #{make_result.branch}\n"
27
+ summary += " Tag: #{make_result.tag}\n"
28
+ summary += " Device: #{make_result.device}\n"
29
+ summary += " Runtime Identifier: #{make_result.runtime_identifier}\n"
30
+ summary += " Initial Size: #{get_humanized_size(make_result.initial_size)}\n"
31
+ summary += " Final Size: #{get_humanized_size(make_result.final_size)}\n"
32
+ summary += " Delta Size: #{get_humanized_size(make_result.final_size - make_result.initial_size)}\n"
33
+ summary += " Commands: (#{make_result.commands.length})\n"
34
+ make_result.commands.each do |command|
35
+ details = get_command_details(command)
36
+ summary += "\n"
37
+ summary += indent_string(details, 4)
38
+ summary += "\n"
39
+ end
40
+
41
+ summary
42
+ end
43
+
44
+ def self.get_commands(commands)
45
+ message = ""
46
+ commands.each do |command|
47
+ message += Makit::Humanize::get_command_details(command)
48
+ end
49
+ message
50
+ end
51
+
52
+ def self.get_command_summary(command)
53
+ symbol = Makit::Symbols.warning
54
+ symbol = Makit::Symbols.checkmark if !command.exit_code.nil? && command.exit_code.zero?
55
+ symbol = Makit::Symbols.error if command.exit_code != 0
56
+ "#{symbol} #{command.name} #{command.arguments.join(" ")}"
57
+ end
58
+
59
+ def self.get_command_details(command)
60
+ summary = "#{get_command_summary(command)}\n"
61
+ summary += " Name: #{command.name}\n"
62
+ summary += " Arguments: #{command.arguments.join(" ")}\n"
63
+ summary += " Directory: #{command.directory}\n"
64
+ summary += " Exit Code: #{command.exit_code}\n"
65
+ if command.output.length > 0
66
+ summary += " Output:\n"
67
+ summary += indent_string(command.output, 4)
68
+ summary += "\n"
69
+ end
70
+ if command.error.length > 0
71
+ summary += " Error:\n"
72
+ summary += indent_string(command.error, 4)
73
+ summary += "\n"
74
+ end
75
+ summary
76
+ end
77
+
78
+ def self.indent_string(string, spaces)
79
+ string.split("\n").map { |line| " " * spaces + line }.join("\n")
80
+ end
81
+
82
+ def self.get_protobuf_timestamp(timestamp)
83
+ Time.at(timestamp.seconds, timestamp.nanos / 1000.0).strftime("%Y-%m-%d %H:%M:%S")
84
+ end
85
+
86
+ def self.get_protobuf_duration(duration)
87
+ total_seconds = duration.seconds + (duration.nanos / 1_000_000_000.0)
88
+ hours = (total_seconds / 3600).to_i
89
+ minutes = ((total_seconds % 3600) / 60).to_i
90
+ seconds = (total_seconds % 60).round(2)
91
+ "#{hours}h #{minutes}m #{seconds}s"
92
+ end
93
+
94
+ def self.get_humanized_duration(seconds_value)
95
+ minutes = (seconds_value / 60).to_i
96
+ seconds = (seconds_value % 60).to_i
97
+ hours = (minutes / 60).to_i
98
+ minutes = minutes % 60
99
+ days = (hours / 24).to_i
100
+ hours = hours % 24
101
+ milliseconds = (seconds_value % 1 * 1000).to_i
102
+
103
+ parts = []
104
+ parts << "#{days} days" if days > 0
105
+ parts << "#{hours} hours" if hours > 0
106
+ if (minutes > 0)
107
+ if (minutes == 1)
108
+ parts << "1 minute"
109
+ else
110
+ parts << "#{minutes} minutes"
111
+ end
112
+ end
113
+ if (seconds > 0)
114
+ if (seconds == 1)
115
+ parts << "1 second"
116
+ else
117
+ parts << "#{seconds} seconds"
118
+ end
119
+ end
120
+ #parts << "#{seconds} seconds" if seconds > 0
121
+ parts << "#{milliseconds} milliseconds" if milliseconds > 0 && seconds < 1
122
+
123
+ if (parts.length == 0)
124
+ parts << "0 seconds"
125
+ end
126
+ parts.join(", ")
127
+ end
128
+ end
129
+ end