smc-get 0.2.0.beta1 → 0.3.0.beta1

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.
@@ -1,117 +1,181 @@
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 display correctly; 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(cui, args)
51
- @cui = cui
52
- parse(args)
53
- end
54
-
55
- #This method gets all commandline options relevant for this subcommand
56
- #passed in the +args+ array. You should parse them destructively, i.e.
57
- #after you finished parsing, +args+ should be an empty array.
58
- #Set instance variables to save data.
59
- #
60
- #Note that SmcGet is not set up when this method is called, so you
61
- #cannot do things like <tt>Package.new</tt>.
62
- def parse(args)
63
- raise(NotImplementedError, "#{__method__} has to be overriden in a subclass!")
64
- end
65
-
66
- #Execute the command. You can use the instance variables set in #parse.
67
- #The method gets passed the parsed contents of smc-get's configuration
68
- #files and commandline parameters; you can use this to make your command
69
- #configurable via the configuration file, but make sure that
70
- #1. The keys you use for your configuration don't already exist,
71
- #2. options specified on the commandline take precedence over values
72
- # set in the configuration file and
73
- #3. you <b>do not alter</b> the hash.
74
- def execute(config)
75
- raise(NotImplementedError, "#{__method__} has to be overriden in a subclass!")
76
- end
77
-
78
- private
79
-
80
- #Downloads the package identified by +pkgname+ and displays the progress to the
81
- #user. Example:
82
- # download_package("cool_world")
83
- #downloads the package "cool_world.smcpak". You mustn’t specify the file
84
- #extension <tt>.smcpak</tt>.
85
- def download_package(pkgname)
86
- pkg_file = "#{pkgname}.smcpak"
87
- #Windows doesn't understand ANSI escape sequences, so we have to
88
- #use the carriage return and reprint the whole line.
89
- base_str = "\rDownloading %s... (%.2f%%)"
90
- tries = 0
91
- begin
92
- tries += 1
93
- path_to_package = @cui.remote_repository.fetch_package(pkg_file, SmcGet.temp_dir) do |bytes_total, bytes_done|
94
- percent = ((bytes_done.to_f / bytes_total) * 100)
95
- print "\r", " " * 80 #Clear everything written before
96
- printf(base_str, pkg_file, percent)
97
- end
98
- rescue OpenURI::HTTPError => e #Thrown even in case of FTP and HTTPS
99
- if tries >= 3
100
- raise #Bubble up
101
- else
102
- $stderr.puts("ERROR: #{e.message}")
103
- $stderr.puts("Retrying.")
104
- retry
105
- end
106
- end
107
- puts #Terminating \n
108
- return path_to_package
109
- end
110
-
111
- end
112
-
113
- end
114
-
115
- end
116
-
117
- # vim:set ts=8 sts=2 sw=2 et: #
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 display correctly; 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(cui, args)
51
+ @cui = cui
52
+ parse(args)
53
+ end
54
+
55
+ #This method gets all commandline options relevant for this subcommand
56
+ #passed in the +args+ array. You should parse them destructively, i.e.
57
+ #after you finished parsing, +args+ should be an empty array.
58
+ #Set instance variables to save data.
59
+ #
60
+ #Note that SmcGet is not set up when this method is called, so you
61
+ #cannot do things like <tt>Package.new</tt>.
62
+ def parse(args)
63
+ raise(NotImplementedError, "#{__method__} has to be overriden in a subclass!")
64
+ end
65
+
66
+ #Execute the command. You can use the instance variables set in #parse.
67
+ #The method gets passed the parsed contents of smc-get's configuration
68
+ #files and commandline parameters; you can use this to make your command
69
+ #configurable via the configuration file, but make sure that
70
+ #1. The keys you use for your configuration don't already exist,
71
+ #2. options specified on the commandline take precedence over values
72
+ # set in the configuration file and
73
+ #3. you <b>do not alter</b> the hash.
74
+ def execute(config)
75
+ raise(NotImplementedError, "#{__method__} has to be overriden in a subclass!")
76
+ end
77
+
78
+ private
79
+
80
+ #Downloads the package identified by +pkgname+ and displays the progress to the
81
+ #user. Example:
82
+ # download_package("cool_world")
83
+ #downloads the package "cool_world.smcpak". You mustn’t specify the file
84
+ #extension <tt>.smcpak</tt>.
85
+ def download_package(pkgname)
86
+ pkg_file = "#{pkgname}.smcpak"
87
+ #Windows doesn't understand ANSI escape sequences, so we have to
88
+ #use the carriage return and reprint the whole line.
89
+ base_str = "\rDownloading %s... (%.2f%%)"
90
+ tries = 0
91
+ begin
92
+ tries += 1
93
+ path_to_package = @cui.remote_repository.fetch_package(pkg_file, SmcGet.temp_dir) do |bytes_total, bytes_done|
94
+ percent = ((bytes_done.to_f / bytes_total) * 100)
95
+ print "\r", " " * 80 #Clear everything written before
96
+ printf(base_str, pkg_file, percent)
97
+ end
98
+ rescue OpenURI::HTTPError => e #Thrown even in case of FTP and HTTPS
99
+ if tries >= 3
100
+ raise #Bubble up
101
+ else
102
+ $stderr.puts("ERROR: #{e.message}")
103
+ $stderr.puts("Retrying.")
104
+ retry
105
+ end
106
+ end
107
+ puts #Terminating \n
108
+ return path_to_package
109
+ end
110
+
111
+ #Recursively installs a package and all of it’s dependencies and their dependencies and so on.
112
+ #+pkg_name+ doesn’t include the .smcpak file extension. The +dep_list+ argument is filled
113
+ #during the recursion with all encountered package to prevent endless recursion in case
114
+ #of circular dependencies and +is_dep+ determines during the recursion wheather or not
115
+ #the currently checked package is to be treated as a dependency (used to
116
+ #spit out a note on --reinstall if the package is already installed). +reinstall+ determines
117
+ #wheather or not a package already installed shall be reinstalled (this affects the dependencies
118
+ #as well).
119
+ def install_package_with_deps(pkg_name, reinstall = false, dep_list = [], is_dep = false)
120
+ if dep_list.include?(pkg_name)
121
+ $stderr.puts("WARNING: Circular dependency detected, skipping additional #{pkg_name}!")
122
+ return
123
+ end
124
+ dep_list << pkg_name
125
+
126
+ if @cui.local_repository.contains?(pkg_name)
127
+ if reinstall
128
+ puts "Reinstalling #{pkg_name}."
129
+ else
130
+ puts "#{pkg_name} is already installed. Maybe you want --reinstall?" unless is_dep
131
+ return
132
+ end
133
+ end
134
+
135
+ puts "Downloading #{pkg_name}..."
136
+ path = download_package(pkg_name)
137
+ pkg = Package.from_file(path)
138
+
139
+ puts "Resolving dependencies for #{pkg_name}..."
140
+ pkg.spec.dependencies.each{|dep| install_package_with_deps(dep, reinstall, dep_list, true)}
141
+
142
+ puts "Installing #{pkg_name}..."
143
+ puts pkg.spec.install_message if pkg.spec.install_message
144
+ @cui.local_repository.install(pkg)
145
+ end
146
+
147
+ #Removes a package from the local repository. +pkg_name+ is the name of the
148
+ #package without any file extension, +ignore_deps+ determines wheather or not
149
+ #to uninstall even if other packages depend on the target and +ignore_conflicts+
150
+ #indicates wheather to prompt the user for action if a modified file is
151
+ #encountered (if set to true, modified files are deleted).
152
+ def uninstall_package(pkg_name, ignore_deps = false, ignore_conflicts = false)
153
+ #Check if a dependency conflict exists
154
+ unless ignore_deps
155
+ puts "Checking for dependencies on #{pkg_name}..."
156
+ specs = @cui.local_repository.package_specs.reject{|spec| spec.name == pkg_name} #A package ought to not depend on itself
157
+ if (i = specs.index{|spec| spec.dependencies.include?(pkg_name)}) #Single equal sign intended
158
+ puts "The package #{specs[i].name} depends on #{pkg_name}."
159
+ print "Remove it anyway?(y/n) "
160
+ raise(Errors::BrokenPackageError, "Can't uninstall #{pkg_name} due to dependency reasons!") unless $stdin.gets.chomp == "y"
161
+ end
162
+ end
163
+ #Real remove operation
164
+ puts "Removing files for #{pkg_name}..."
165
+ @cui.local_repository.uninstall(pkg_name) do |conflict|
166
+ next(false) if ignore_conflicts
167
+ puts "CONFLICT: The file #{conflict} has been modified. What now?"
168
+ puts "1) Ignore and delete anyway"
169
+ puts "2) Copy file and include MODIFIED in the name."
170
+ print "Enter a number[1]: "
171
+ $stdin.gets.chomp.to_i == 2 #True means copying
172
+ end
173
+ end
174
+
175
+ end
176
+
177
+ end
178
+
179
+ end
180
+
181
+ # vim:set ts=8 sts=2 sw=2 et: #
@@ -1,92 +1,92 @@
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
- Dir.mktmpdir do |tmpdir|
65
- repo = if @cui.local_repository.contains?(@pkg_name) and !@force_remote
66
- puts "[LOCAL PACKAGE]"
67
- @cui.local_repository
68
- else
69
- puts "[REMOTE PACKAGE]"
70
- @cui.remote_repository
71
- end
72
- info = YAML.load_file(repo.fetch_spec(@pkg_name + ".yml", tmpdir).to_s)
73
-
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{|author| puts " - #{author}"}
80
- end
81
- puts "Difficulty: #{info['difficulty']}"
82
- puts "Description: #{info['description']}"
83
- end
84
-
85
- end
86
-
87
- end
88
-
89
- end
90
-
91
- end
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
+ Dir.mktmpdir do |tmpdir|
65
+ repo = if @cui.local_repository.contains?(@pkg_name) and !@force_remote
66
+ puts "[LOCAL PACKAGE]"
67
+ @cui.local_repository
68
+ else
69
+ puts "[REMOTE PACKAGE]"
70
+ @cui.remote_repository
71
+ end
72
+ info = YAML.load_file(repo.fetch_spec(@pkg_name + ".yml", tmpdir).to_s)
73
+
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{|author| puts " - #{author}"}
80
+ end
81
+ puts "Difficulty: #{info['difficulty']}"
82
+ puts "Description: #{info['description']}"
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ end
92
92
  # vim:set ts=8 sts=2 sw=2 et: #