smc-get 0.2.0.beta1 → 0.3.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: #