smc-get 0.1.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.
- data/COPYING +674 -0
- data/README.rdoc +148 -0
- data/VERSION.txt +1 -0
- data/bin/smc-get +31 -0
- data/config/smc-get.yml +32 -0
- data/lib/smc_get.rb +21 -0
- data/lib/smc_get/cui.rb +289 -0
- data/lib/smc_get/cui_commands/command.rb +81 -0
- data/lib/smc_get/cui_commands/getinfo.rb +91 -0
- data/lib/smc_get/cui_commands/help.rb +64 -0
- data/lib/smc_get/cui_commands/install.rb +91 -0
- data/lib/smc_get/cui_commands/list.rb +80 -0
- data/lib/smc_get/cui_commands/search.rb +109 -0
- data/lib/smc_get/cui_commands/uninstall.rb +78 -0
- data/lib/smc_get/cui_commands/version.rb +57 -0
- data/lib/smc_get/errors.rb +113 -0
- data/lib/smc_get/gui.rb +19 -0
- data/lib/smc_get/package.rb +279 -0
- data/lib/smc_get/smc_get.rb +139 -0
- data/test/test_smc-get-cui.rb +121 -0
- data/test/test_smc-get-lib.rb +170 -0
- metadata +87 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
#Encoding: UTF-8
|
2
|
+
################################################################################
|
3
|
+
# This file is part of smc-get.
|
4
|
+
# Copyright (C) 2010-2011 Entertaining Software, Inc.
|
5
|
+
# Copyright (C) 2011 Marvin Gülker
|
6
|
+
#
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
################################################################################
|
20
|
+
|
21
|
+
module SmcGet
|
22
|
+
|
23
|
+
module CUICommands
|
24
|
+
|
25
|
+
#Class for invalid command-line argument errors.
|
26
|
+
class InvalidCommandline < Errors::SmcGetError
|
27
|
+
end
|
28
|
+
|
29
|
+
#This is the superclass of all CUI commands. To make your own command,
|
30
|
+
#subclass it an overwrite ::help, ::summary, #parse and #execute.
|
31
|
+
class Command
|
32
|
+
|
33
|
+
#The string returned from this method will be displayed to the
|
34
|
+
#user if he issues <tt>smc-get help YOURCOMMAND</tt>.
|
35
|
+
def self.help
|
36
|
+
"(nothing known)"
|
37
|
+
end
|
38
|
+
|
39
|
+
#One-line summary of the command that shows up in the COMMANDS
|
40
|
+
#section of <tt>smc-get help</tt>. Should not be longer than 78
|
41
|
+
#characters due to automatic indentation. You may have to insert
|
42
|
+
#tabs to make it displaycorrectly; make sure to check the result by
|
43
|
+
#issueing <tt>smc-get help</tt>.
|
44
|
+
def self.summary
|
45
|
+
""
|
46
|
+
end
|
47
|
+
|
48
|
+
#Creates a new instance of this command. Do not override this, or
|
49
|
+
#call at least +super+.
|
50
|
+
def initialize(args)
|
51
|
+
parse(args)
|
52
|
+
end
|
53
|
+
|
54
|
+
#This method gets all commandline options relevant for this subcommand
|
55
|
+
#passed in the +args+ array. You should parse them destructively, i.e.
|
56
|
+
#after you finished parsing, +args+ should be an empty array.
|
57
|
+
#Set instance variables to save data.
|
58
|
+
#
|
59
|
+
#Note that SmcGet is not set up when this method is called, so you
|
60
|
+
#cannot to things like <tt>Package.new</tt>.
|
61
|
+
def parse(args)
|
62
|
+
raise(NotImplementedError, "#{__method__} has to be overriden in a subclass!")
|
63
|
+
end
|
64
|
+
|
65
|
+
#Execute the command. You can use the instance variables set in #parse.
|
66
|
+
#The method gets passed the parsed contents of smc-get's configuration
|
67
|
+
#files and commandline parameters; you can use this to make your command
|
68
|
+
#configurable via the configuration file, but make sure that
|
69
|
+
#1. The keys you use for your configuration don't already exist,
|
70
|
+
#2. options specified on the commandline take precedence over values
|
71
|
+
# set in the configuration file and
|
72
|
+
#3. you <b>do not alter</b> the hash.
|
73
|
+
def execute(config)
|
74
|
+
raise(NotImplementedError, "#{__method__} has to be overriden in a subclass!")
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
#Encoding: UTF-8
|
2
|
+
################################################################################
|
3
|
+
# This file is part of smc-get.
|
4
|
+
# Copyright (C) 2010-2011 Entertaining Software, Inc.
|
5
|
+
# Copyright (C) 2011 Marvin Gülker
|
6
|
+
#
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
################################################################################
|
20
|
+
|
21
|
+
module SmcGet
|
22
|
+
|
23
|
+
module CUICommands
|
24
|
+
|
25
|
+
class GetinfoCommand < Command
|
26
|
+
|
27
|
+
def self.help
|
28
|
+
<<HELP
|
29
|
+
USAGE: #{File.basename($0)} getinfo [-r] PACKAGE
|
30
|
+
|
31
|
+
Retrieves information about PACKAGE.
|
32
|
+
|
33
|
+
OPTIONS:
|
34
|
+
\r-r\t--remote\tForces getinfo to do a remote lookup.
|
35
|
+
|
36
|
+
The default behaviour is to do a local lookup if the
|
37
|
+
package is already installed.
|
38
|
+
HELP
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.summary
|
42
|
+
"getinfo\tGet information on a package."
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse(args)
|
46
|
+
CUI.debug("Parsing #{args.count} args for getinfo.")
|
47
|
+
raise(InvalidCommandline, "No package given.") if args.empty?
|
48
|
+
@force_remote = false
|
49
|
+
|
50
|
+
while args.count > 1
|
51
|
+
arg = args.shift
|
52
|
+
case arg
|
53
|
+
when "-r", "--remote" then @force_remote = true
|
54
|
+
else
|
55
|
+
raise(InvalidCommandline, "Invalid argument #{arg}.")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
#The last command-line arg is the package
|
59
|
+
@pkg_name = args.shift
|
60
|
+
end
|
61
|
+
|
62
|
+
def execute(config)
|
63
|
+
CUI.debug("Executing getinfo.")
|
64
|
+
pkg = Package.new(@pkg_name)
|
65
|
+
#Get the information
|
66
|
+
info = if pkg.installed? and !@force_remote
|
67
|
+
puts "[LOCAL PACKAGE]"
|
68
|
+
pkg.spec
|
69
|
+
else
|
70
|
+
puts "[REMOTE PACKAGE]"
|
71
|
+
pkg.getinfo
|
72
|
+
end
|
73
|
+
#Now output the information
|
74
|
+
puts "Title: #{info['title']}"
|
75
|
+
if info['authors'].count == 1
|
76
|
+
puts "Author: #{info['authors'][0]}"
|
77
|
+
else
|
78
|
+
puts 'Authors:'
|
79
|
+
info['authors'].each do |author|
|
80
|
+
puts " - #{author}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
puts "Difficulty: #{info['difficulty']}"
|
84
|
+
puts "Description: #{info['description']}"
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
#Encoding: UTF-8
|
2
|
+
################################################################################
|
3
|
+
# This file is part of smc-get.
|
4
|
+
# Copyright (C) 2010-2011 Entertaining Software, Inc.
|
5
|
+
# Copyright (C) 2011 Marvin Gülker
|
6
|
+
#
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
################################################################################
|
20
|
+
|
21
|
+
module SmcGet
|
22
|
+
|
23
|
+
module CUICommands
|
24
|
+
|
25
|
+
class HelpCommand < Command
|
26
|
+
|
27
|
+
def self.help
|
28
|
+
<<EOF
|
29
|
+
USAGE: #{File.basename($0)} help [SUBCOMMAND]
|
30
|
+
|
31
|
+
Shows help for a special SUBCOMMAND or for #{File.basename($0)} in general.
|
32
|
+
EOF
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.summary
|
36
|
+
"help\t\tGet help on a specific command."
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse(args)
|
40
|
+
CUI.debug("Parsing #{args.count} args for help.")
|
41
|
+
raise(InvalidCommandline, "Too many arguments.") if args.count > 1
|
42
|
+
@command = args.shift #nil if not given
|
43
|
+
end
|
44
|
+
|
45
|
+
def execute(config)
|
46
|
+
CUI.debug("Executing help.")
|
47
|
+
if @command
|
48
|
+
sym = :"#{@command.capitalize}Command"
|
49
|
+
if CUICommands.const_defined?(sym)
|
50
|
+
puts CUICommands.const_get(sym).help
|
51
|
+
else
|
52
|
+
puts "#{@command} is not a valid command."
|
53
|
+
return 2
|
54
|
+
end
|
55
|
+
else
|
56
|
+
puts CUI::GENERAL_HELP
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
#Encoding: UTF-8
|
2
|
+
################################################################################
|
3
|
+
# This file is part of smc-get.
|
4
|
+
# Copyright (C) 2010-2011 Entertaining Software, Inc.
|
5
|
+
# Copyright (C) 2011 Marvin Gülker
|
6
|
+
#
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
################################################################################
|
20
|
+
|
21
|
+
module SmcGet
|
22
|
+
|
23
|
+
module CUICommands
|
24
|
+
|
25
|
+
class InstallCommand < Command
|
26
|
+
|
27
|
+
def self.help
|
28
|
+
<<HELP
|
29
|
+
USAGE: #{File.basename($0)} install [-r] PACKAGES
|
30
|
+
|
31
|
+
Installs one or more packages.
|
32
|
+
|
33
|
+
OPTIONS:
|
34
|
+
-r\t--reinstall\tForces a reinstallation of the package.
|
35
|
+
HELP
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.summary
|
39
|
+
"install\tInstall one or more packages."
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse(args)
|
43
|
+
CUI.debug("Parsing #{args.count} args for install.")
|
44
|
+
raise(InvalidCommandline, "No package given.") if args.empty?
|
45
|
+
@reinstall = false
|
46
|
+
@pkg_names = []
|
47
|
+
|
48
|
+
until args.empty?
|
49
|
+
arg = args.shift
|
50
|
+
case arg
|
51
|
+
when "--reinstall", "-r" then @reinstall = true
|
52
|
+
else
|
53
|
+
@pkg_names << arg
|
54
|
+
$stderr.puts("Unknown argument #{arg}. Treating it as a package.") if arg.start_with?("-")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def execute(config)
|
60
|
+
CUI.debug("Executing install.")
|
61
|
+
@pkg_names.each do |pkg_name|
|
62
|
+
pkg = Package.new(pkg_name)
|
63
|
+
if pkg.installed?
|
64
|
+
if @reinstall
|
65
|
+
puts "Reinstalling #{pkg}."
|
66
|
+
else
|
67
|
+
puts "#{pkg} is already installed. Maybe you want --reinstall?."
|
68
|
+
next
|
69
|
+
end
|
70
|
+
end
|
71
|
+
puts "Installing #{pkg}."
|
72
|
+
#Windows doesn't understand ANSI escape sequences, so we have to
|
73
|
+
#use the carriage return and reprint the whole line.
|
74
|
+
base_str = "\rDownloading %s... (%.2f%%)"
|
75
|
+
pkg.install(config[:max_tries]) do |filename, percent_filename, retrying|
|
76
|
+
if retrying
|
77
|
+
puts "#{retrying.message} Retrying."
|
78
|
+
else
|
79
|
+
print "\r", " " * 80 #Clear everything written before
|
80
|
+
printf(base_str, filename, percent_filename)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
puts
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#Encoding: UTF-8
|
2
|
+
################################################################################
|
3
|
+
# This file is part of smc-get.
|
4
|
+
# Copyright (C) 2010-2011 Entertaining Software, Inc.
|
5
|
+
# Copyright (C) 2011 Marvin Gülker
|
6
|
+
#
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
################################################################################
|
20
|
+
|
21
|
+
module SmcGet
|
22
|
+
|
23
|
+
module CUICommands
|
24
|
+
|
25
|
+
class ListCommand < Command
|
26
|
+
|
27
|
+
def self.help
|
28
|
+
<<EOF
|
29
|
+
USAGE: #{File.basename($0)} list [PACKAGE]
|
30
|
+
|
31
|
+
If PACKAGE is given, lists all files installed by PACKAGE. Otherwise,
|
32
|
+
all installed packages are listed accompanied by their installation
|
33
|
+
date in the format YY-MM-DD HH:MM, where the time is given on a
|
34
|
+
24-hour clock.
|
35
|
+
EOF
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.summary
|
39
|
+
"list\t\tLists all installed packages or files installed by a package. "
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse(args)
|
43
|
+
CUI.debug("Parsing #{args.count} args for list.")
|
44
|
+
raise(InvalidCommandline, "Too many arguments.") if args.count > 1
|
45
|
+
@pkg_name = args.shift #nil if not specified
|
46
|
+
end
|
47
|
+
|
48
|
+
def execute(config)
|
49
|
+
CUI.debug("Executing help.")
|
50
|
+
if Package.installed_packages.empty?
|
51
|
+
puts "No packages installed."
|
52
|
+
else
|
53
|
+
if @pkg_name
|
54
|
+
pkg = Package.new(@pkg_name)
|
55
|
+
puts "Files installed for #{pkg}:"
|
56
|
+
info = pkg.spec
|
57
|
+
puts
|
58
|
+
puts "Levels:"
|
59
|
+
puts info["levels"].join("\n")
|
60
|
+
puts
|
61
|
+
puts "Music:"
|
62
|
+
puts info.has_key?("music") ? info["music"].join("\n") : "(None)"
|
63
|
+
puts
|
64
|
+
puts "Graphics:"
|
65
|
+
puts info.has_key?("graphics") ? info["graphics"].join("\n") : "(None)"
|
66
|
+
else
|
67
|
+
printf("%-38s | %-38s\n", "Package", "Installation date")
|
68
|
+
print("-" * 39, "+", "-" * 40, "\n")
|
69
|
+
Package.installed_packages.each do |pkg|
|
70
|
+
printf("%-38s | %-38s\n", pkg.name, pkg.spec_file.mtime.strftime("%d-%m-%Y %H:%M"))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
#Encoding: UTF-8
|
2
|
+
################################################################################
|
3
|
+
# This file is part of smc-get.
|
4
|
+
# Copyright (C) 2010-2011 Entertaining Software, Inc.
|
5
|
+
# Copyright (C) 2011 Marvin Gülker
|
6
|
+
#
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
################################################################################
|
20
|
+
|
21
|
+
module SmcGet
|
22
|
+
|
23
|
+
module CUICommands
|
24
|
+
|
25
|
+
class SearchCommand < Command
|
26
|
+
|
27
|
+
def self.help
|
28
|
+
<<HELP
|
29
|
+
USAGE: #{File.basename($0)} search [-a][-d][-D][-l][-L][-p][-t] QUERY
|
30
|
+
|
31
|
+
Searches the local or remote repository for packages. QUERY is assumed
|
32
|
+
to be a regular expression.
|
33
|
+
|
34
|
+
OPTIONS:
|
35
|
+
-a\t--authors\tSearch the author list.
|
36
|
+
-d\t--description\tSearch the package descriptions.
|
37
|
+
-D\t--difficulty\tSearch the 'difficulty' fields.
|
38
|
+
-l\t--only-local\tOnly search local packages. Default is to search remotely.
|
39
|
+
-L\t--levels\tSearch for specific level names.
|
40
|
+
-p\t--pkgname\tSearch the package files' names.
|
41
|
+
-t\t--title\t\tSearch the packages' full titles.
|
42
|
+
|
43
|
+
|
44
|
+
If you don't specify which fields to use, --pkgname is assumed as it performs
|
45
|
+
best if used alone.
|
46
|
+
HELP
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.summary
|
50
|
+
"search\tSearch for a package."
|
51
|
+
end
|
52
|
+
|
53
|
+
def parse(args)
|
54
|
+
CUI.debug("Parsing #{args.count} args for search.")
|
55
|
+
raise(InvalidCommandline, "No query given.") if args.empty?
|
56
|
+
@search_fields = []
|
57
|
+
@only_local = false
|
58
|
+
|
59
|
+
while args.count > 1
|
60
|
+
arg = args.shift
|
61
|
+
case arg
|
62
|
+
when "-l", "--only-local" then @only_local = true
|
63
|
+
when "-t", "--title" then @search_fields << :title
|
64
|
+
when "-d", "--description" then @search_fields << :description
|
65
|
+
when "-a", "--authors" then @search_fields << :authors
|
66
|
+
when "-D", "--difficulty" then @search_fields << :difficulty
|
67
|
+
when "-L", "--levels" then @search_fields << :levels
|
68
|
+
when "-p", "--pkgname" then @search_fields << :pkgname
|
69
|
+
else
|
70
|
+
raise(InvalidCommandline, "Invalid argument #{arg}.")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
#If no search fields were specified, default to :pkgname, because
|
74
|
+
#it causes the least network traffic.
|
75
|
+
@search_fields << :pkgname if @search_fields.empty?
|
76
|
+
#The last command-line arg is the search query
|
77
|
+
@query = Regexp.new(args.shift)
|
78
|
+
end
|
79
|
+
|
80
|
+
def execute(config)
|
81
|
+
CUI.debug("Executing search.")
|
82
|
+
result = SmcGet::Package.search(@query, @search_fields, @only_local)
|
83
|
+
return 2 if result.empty?
|
84
|
+
result.each do |pkg|
|
85
|
+
#We need to check the only_local option here, because the level
|
86
|
+
#version in the repository may be newer than that one installed
|
87
|
+
#locally. pkg.installed? wouldn't have telled us that.
|
88
|
+
spec = if @only_local
|
89
|
+
puts "[LOCAL PACKAGE]"
|
90
|
+
pkg.spec
|
91
|
+
else
|
92
|
+
puts "[REMOTE PACKAGE]"
|
93
|
+
pkg.getinfo
|
94
|
+
end
|
95
|
+
puts "Package title: #{spec["title"]}"
|
96
|
+
puts "Real package name: #{pkg.name}"
|
97
|
+
puts "Authors: #{spec["authors"].join(",")}"
|
98
|
+
puts "Difficulty: #{spec["difficulty"]}"
|
99
|
+
puts "Description:"
|
100
|
+
puts spec["description"]
|
101
|
+
puts
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|