aptly 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,255 @@
1
+ module Aptly
2
+ extend self
3
+
4
+ # Creates a new repository in aptly
5
+ #
6
+ # == Parameters:
7
+ # name::
8
+ # The name to use for the new repository
9
+ # dist::
10
+ # The distribution used during publishing
11
+ # comment::
12
+ # A comment describing the repository
13
+ # component::
14
+ # The component used during publishing
15
+ #
16
+ # == Returns:
17
+ # An Aptly::Repo object
18
+ #
19
+ def create_repo name, kwargs={}
20
+ dist = kwargs.arg :dist, ''
21
+ comment = kwargs.arg :comment, ''
22
+ component = kwargs.arg :component, 'main'
23
+ if list_repos.include? name
24
+ raise AptlyError.new("Repo '#{name}' already exists")
25
+ end
26
+
27
+ cmd = "aptly repo create"
28
+ cmd += " -comment=#{comment.quote}" if !comment.empty?
29
+ cmd += " -distribution=#{dist.quote}" if !dist.empty?
30
+ cmd += " #{name}"
31
+
32
+ runcmd cmd
33
+ return Repo.new name
34
+ end
35
+
36
+ # Return a list of existing repositories
37
+ #
38
+ # == Returns
39
+ # An array of strings representing repository names
40
+ #
41
+ def list_repos
42
+ out = runcmd 'aptly repo list'
43
+ parse_list out.lines
44
+ end
45
+
46
+ # Retrieve information about a repository
47
+ #
48
+ # == Parameters:
49
+ # name::
50
+ # The name of the repository to retrieve information for
51
+ #
52
+ # == Returns:
53
+ # A hash of repository information
54
+ #
55
+ def repo_info name
56
+ out = runcmd "aptly repo show #{name.quote}"
57
+ parse_info out.lines
58
+ end
59
+
60
+ class Repo
61
+ attr_accessor :name, :dist, :component
62
+ attr_accessor :comment, :num_packages, :archlist
63
+
64
+ @name = ''
65
+ @dist = ''
66
+ @component = ''
67
+ @comment = ''
68
+ @num_packages = 0
69
+
70
+ # Instantiates an Aptly::Repo object
71
+ #
72
+ # == Parameters:
73
+ # name::
74
+ # The name of the repository
75
+ #
76
+ # == Returns:
77
+ # An Aptly::Repo object
78
+ #
79
+ def initialize name
80
+ if !Aptly::list_repos.include? name
81
+ raise AptlyError.new "Repo '#{name}' does not exist"
82
+ end
83
+
84
+ info = Aptly::repo_info name
85
+ @name = info['Name']
86
+ @comment = info['Comment']
87
+ @dist = info['Default Distribution']
88
+ @component = info['Default Component']
89
+ @num_packages = info['Number of packages'].to_i
90
+ end
91
+
92
+ # Drops an existing aptly repository
93
+ def drop
94
+ Aptly::runcmd "aptly repo drop #{@name.quote}"
95
+ end
96
+
97
+ # List all packages contained in a repository
98
+ #
99
+ # == Returns:
100
+ # An array of packages
101
+ #
102
+ def list_packages
103
+ res = []
104
+ out = Aptly::runcmd "aptly repo show -with-packages #{@name.quote}"
105
+ Aptly::parse_indented_list out.lines
106
+ end
107
+
108
+ # Add debian packages to a repo
109
+ #
110
+ # == Parameters:
111
+ # path::
112
+ # The path to the file or directory source
113
+ # remove_files::
114
+ # When true, deletes source after import
115
+ #
116
+ def add path, kwargs={}
117
+ remove_files = kwargs.arg :remove_files, false
118
+
119
+ cmd = 'aptly repo add'
120
+ cmd += ' -remove-files' if remove_files
121
+ cmd += " #{@name.quote} #{path}"
122
+
123
+ Aptly::runcmd cmd
124
+ end
125
+
126
+ # Imports package resources from existing mirrors
127
+ #
128
+ # == Parameters:
129
+ # from_mirror::
130
+ # The name of the mirror to import from
131
+ # packages::
132
+ # A list of debian pkg_spec strings (e.g. "libc6 (>= 2.7-1)")
133
+ # deps::
134
+ # When true, follows package dependencies and adds them
135
+ #
136
+ def import from_mirror, kwargs={}
137
+ deps = kwargs.arg :deps, false
138
+ packages = kwargs.arg :packages, []
139
+
140
+ if packages.length == 0
141
+ raise AptlyError.new '1 or more packages are required'
142
+ end
143
+
144
+ cmd = 'aptly repo import'
145
+ cmd += ' -with-deps' if deps
146
+ cmd += " #{from_mirror.quote} #{@name.quote}"
147
+ packages.each {|p| cmd += " #{p.quote}"}
148
+
149
+ Aptly::runcmd cmd
150
+ end
151
+
152
+ # Copy package resources from one repository to another
153
+ #
154
+ # == Parameters:
155
+ # from_repo::
156
+ # The source repository name
157
+ # to_repo::
158
+ # The destination repository name
159
+ # pkg_spec::
160
+ # A debian pkg_spec string
161
+ # deps::
162
+ # When true, follow deps and copy them
163
+ #
164
+ def copy from_repo, to_repo, pkg_spec, kwargs={}
165
+ deps = kwargs.arg :deps, false
166
+
167
+ cmd = 'aptly repo copy'
168
+ cmd += ' -with-deps' if deps
169
+ cmd += " #{from_repo.quote} #{to_repo.quote} #{pkg_spec.quote}"
170
+
171
+ Aptly::runcmd cmd
172
+ end
173
+ private :copy
174
+
175
+ # Shortcut method to copy resources in from another repository
176
+ def copy_from from_repo, pkg_spec, kwargs={}
177
+ deps = kwargs.arg :deps, false
178
+ copy from_repo, @name, pkg_spec, :deps => deps
179
+ end
180
+
181
+ # Shortcut method to copy resources out to another repository
182
+ def copy_to to_repo, pkg_spec, kwargs={}
183
+ deps = kwargs.arg :deps, false
184
+ copy @name, to_repo, pkg_spec, :deps => deps
185
+ end
186
+
187
+ # Move package resources from one repository to another
188
+ #
189
+ # == Parameters:
190
+ # from_repo::
191
+ # The source repository name
192
+ # to_repo::
193
+ # The destination repository name
194
+ # pkg_spec::
195
+ # A debian pkg_spec string
196
+ # deps::
197
+ # When true, follow deps and move them too
198
+ #
199
+ def move from_repo, to_repo, pkg_spec, kwargs={}
200
+ deps = kwargs.arg :deps, false
201
+
202
+ cmd = 'aptly repo move'
203
+ cmd += ' -with-deps' if deps
204
+ cmd += " #{from_repo.quote} #{to_repo.quote} #{pkg_spec.quote}"
205
+
206
+ Aptly::runcmd cmd
207
+ end
208
+ private :move
209
+
210
+ # Shortcut method to move packages in from another repo
211
+ def move_from from_repo, pkg_spec, kwargs={}
212
+ deps = kwargs.arg :deps, false
213
+ move from_repo, @name, pkg_spec, :deps => deps
214
+ end
215
+
216
+ # Shortcut method to move packages out to another repository
217
+ def move_to to_repo, pkg_spec, kwargs={}
218
+ deps = kwargs.arg :deps, false
219
+ move @name, to_repo, pkg_spec, :deps => deps
220
+ end
221
+
222
+ # Remove packages selectively from a repository
223
+ #
224
+ # == Parameters:
225
+ # pkg_spec::
226
+ # A debian pkg_spec string to select packages by
227
+ #
228
+ def remove pkg_spec
229
+ Aptly::runcmd "aptly repo remove #{@name.quote} #{pkg_spec.quote}"
230
+ end
231
+
232
+ # Shortcut method to snapshot an Aptly::Repo object
233
+ def snapshot name
234
+ Aptly::create_repo_snapshot name, @name
235
+ end
236
+
237
+ # Shortcut method to publish a repo from an Aptly::Repo instance.
238
+ def publish args
239
+ Aptly::publish 'repo', @name, args
240
+ end
241
+
242
+ # save allows you to modify the repository distribution, comment, or
243
+ # component string by using the attr_accessor's, and then calling this
244
+ # method to persist them to aptly.
245
+ def save
246
+ cmd = "aptly repo edit"
247
+ cmd += " -distribution=#{@dist.quote}"
248
+ cmd += " -comment=#{@comment.quote}"
249
+ cmd += " -component=#{@component.quote}"
250
+ cmd += " #{@name.quote}"
251
+
252
+ Aptly::runcmd cmd
253
+ end
254
+ end
255
+ end
@@ -0,0 +1,270 @@
1
+ module Aptly
2
+ extend self
3
+
4
+ # Create a new snapshot of a repo or mirror
5
+ #
6
+ # == Parameters:
7
+ # name::
8
+ # The name for the new snapshot
9
+ # type::
10
+ # The type of snapshot. "mirror" and "repo" are supported.
11
+ # resource_name::
12
+ # The name of the mirror or repo
13
+ #
14
+ # == Returns:
15
+ # An Aptly::Snapshot object
16
+ #
17
+ def create_snapshot name, type, kwargs={}
18
+ resource_name = kwargs.arg :resource_name, ''
19
+
20
+ if type != 'mirror' && type != 'repo' && type != 'empty'
21
+ raise AptlyError.new "Invalid snapshot type: #{type}"
22
+ end
23
+
24
+ if list_snapshots.include? name
25
+ raise AptlyError.new "Snapshot '#{name}' exists"
26
+ end
27
+
28
+ if type == 'mirror' && !list_mirrors.include?(resource_name)
29
+ raise AptlyError.new "Mirror '#{resource_name}' does not exist"
30
+ end
31
+
32
+ if type == 'repo' && !list_repos.include?(resource_name)
33
+ raise AptlyError.new "Repo '#{resource_name}' does not exist"
34
+ end
35
+
36
+ cmd = 'aptly snapshot create'
37
+ cmd += " #{name.quote}"
38
+ if type == 'empty'
39
+ cmd += ' empty'
40
+ else
41
+ cmd += " from #{type} #{resource_name.quote}"
42
+ end
43
+
44
+ runcmd cmd
45
+ Snapshot.new name
46
+ end
47
+ private :create_snapshot
48
+
49
+ # Shortcut method to create a snapshot from a mirror
50
+ def create_mirror_snapshot name, mirror_name
51
+ create_snapshot name, 'mirror', :resource_name => mirror_name
52
+ end
53
+
54
+ # Shortcut method to create a snapshot from a repo
55
+ def create_repo_snapshot name, repo_name
56
+ create_snapshot name, 'repo', :resource_name => repo_name
57
+ end
58
+
59
+ # Shortcut method to create an empty snapshot
60
+ def create_empty_snapshot name
61
+ create_snapshot name, 'empty'
62
+ end
63
+
64
+ # List existing snapshots
65
+ #
66
+ # == Returns:
67
+ # A list of snapshot names
68
+ #
69
+ def list_snapshots
70
+ out = runcmd 'aptly snapshot list'
71
+ parse_list out.lines
72
+ end
73
+
74
+ # Retrieves information about a snapshot
75
+ #
76
+ # == Parameters:
77
+ # name::
78
+ # The name of the snapshot to gather information about
79
+ #
80
+ # == Returns:
81
+ # A hash of snapshot information
82
+ #
83
+ def snapshot_info name
84
+ out = runcmd "aptly snapshot show #{name.quote}"
85
+ parse_info out.lines
86
+ end
87
+
88
+ # Merge snapshots into a single snapshot. This will create a new snapshot
89
+ # containing packages from all source snapshots. By default, packages with
90
+ # the same name-architecture pair are merged from right-over-left, meaning
91
+ # packages in the last source snapshot may overwrite the same packages in
92
+ # the first source snapshot if their name-architecture pairs match.
93
+ #
94
+ # == Parameters:
95
+ # dest::
96
+ # The destination snapshot name (will be created)
97
+ # sources::
98
+ # The names of source repositories. The order in which these are passed
99
+ # matters unless `-latest` is not passed.
100
+ # latest::
101
+ # When true, only the latest of each package will be copied into the
102
+ # new snapshot, following a "latest wins" approach.
103
+ #
104
+ # == Returns:
105
+ # An Aptly::Snapshot object for the new snapshot
106
+ #
107
+ def merge_snapshots dest, kwargs={}
108
+ sources = kwargs.arg :sources, []
109
+ latest = kwargs.arg :latest, false
110
+
111
+ if sources.length == 0
112
+ raise AptlyError.new '1 or more sources are required'
113
+ end
114
+
115
+ if list_snapshots.include? dest
116
+ raise AptlyError.new "Snapshot '#{dest}' exists"
117
+ end
118
+
119
+ cmd = 'aptly snapshot merge'
120
+ cmd += ' -latest' if latest
121
+ cmd += " #{dest.quote}"
122
+ cmd += " #{sources.join(' ')}"
123
+
124
+ runcmd cmd
125
+ Aptly::Snapshot.new dest
126
+ end
127
+
128
+ class Snapshot
129
+ attr_accessor :name, :created_at, :description, :num_packages
130
+
131
+ @name = ''
132
+ @created_at = ''
133
+ @description = ''
134
+ @num_packages = 0
135
+
136
+ # Instantiates a new Aptly::Snapshot instance
137
+ #
138
+ # == Parameters:
139
+ # name::
140
+ # The name of the snapshot
141
+ #
142
+ # == Returns:
143
+ # An Aptly::Snapshot instance
144
+ #
145
+ def initialize name
146
+ if !Aptly::list_snapshots.include? name
147
+ raise AptlyError.new("Snapshot '#{name}' does not exist")
148
+ end
149
+
150
+ info = Aptly::snapshot_info name
151
+ @name = info['Name']
152
+ @created_at = info['Created At']
153
+ @description = info['Description']
154
+ @num_packages = info['Number of packages'].to_i
155
+ end
156
+
157
+ # Drops an existing snapshot
158
+ #
159
+ # == Parameters:
160
+ # force::
161
+ # When true, drops a snapshot regardless of relationships
162
+ #
163
+ def drop kwargs={}
164
+ force = kwargs.arg :force, false
165
+
166
+ cmd = 'aptly snapshot drop'
167
+ cmd += ' -force' if force
168
+ cmd += " #{@name.quote}"
169
+
170
+ Aptly::runcmd cmd
171
+ end
172
+
173
+ # List all packages contained in a snapshot
174
+ #
175
+ # == Returns:
176
+ # An array of packages
177
+ #
178
+ def list_packages
179
+ res = []
180
+ out = Aptly::runcmd "aptly snapshot show -with-packages #{@name.quote}"
181
+ Aptly::parse_indented_list out.lines
182
+ end
183
+
184
+ # Pull packages from a snapshot into another, creating a new snapshot.
185
+ #
186
+ # == Parameters:
187
+ # name::
188
+ # The name of the snapshot to pull to
189
+ # source::
190
+ # The repository containing the packages to pull in
191
+ # dest::
192
+ # The name for the new snapshot which will be created
193
+ # packages::
194
+ # An array of package names to search
195
+ # deps::
196
+ # When true, process dependencies
197
+ # remove::
198
+ # When true, removes package versions not found in source
199
+ #
200
+ def pull name, source, dest, kwargs={}
201
+ packages = kwargs.arg :packages, []
202
+ deps = kwargs.arg :deps, true
203
+ remove = kwargs.arg :remove, true
204
+
205
+ if packages.length == 0
206
+ raise AptlyError.new "1 or more package names are required"
207
+ end
208
+
209
+ cmd = 'aptly snapshot pull'
210
+ cmd += ' -no-deps' if !deps
211
+ cmd += ' -no-remove' if !remove
212
+ cmd += " #{name.quote} #{source.quote} #{dest.quote}"
213
+ if !packages.empty?
214
+ packages.each {|p| cmd += " #{p.quote}"}
215
+ end
216
+
217
+ Aptly::runcmd cmd
218
+ Aptly::Snapshot.new dest
219
+ end
220
+ private :pull
221
+
222
+ # Shortcut method to pull packages to the current snapshot
223
+ def pull_from source, dest, kwargs={}
224
+ packages = kwargs.arg :packages, []
225
+ deps = kwargs.arg :deps, true
226
+ remove = kwargs.arg :remove, true
227
+
228
+ pull @name, source, dest, :packages => packages, :deps => deps, :remove => remove
229
+ end
230
+
231
+ # Shortcut method to push packages from the current snapshot
232
+ def push_to dest, source, kwargs={}
233
+ packages = kwargs.arg :packages, []
234
+ deps = kwargs.arg :deps, true
235
+ remove = kwargs.arg :remove, true
236
+
237
+ pull source, @name, dest, :packages => packages, :deps => deps, :remove => remove
238
+ end
239
+
240
+ # Verifies an existing snapshot is able to resolve dependencies. This method
241
+ # currently only returns true/false status.
242
+ #
243
+ # == Parameters:
244
+ # sources::
245
+ # Additional snapshot sources to be considered during verification
246
+ # follow_source::
247
+ # When true, verify all source packages as well
248
+ #
249
+ # == Returns:
250
+ # An array containing any missing deps. Empty list means all verified.
251
+ #
252
+ def verify kwargs={}
253
+ sources = kwargs.arg :sources, []
254
+ follow_source = kwargs.arg :follow_source, false
255
+
256
+ cmd = 'aptly snapshot verify'
257
+ cmd += ' -dep-follow-source' if follow_source
258
+ cmd += " #{@name.quote}"
259
+ cmd += " #{sources.join(' ')}" if !sources.empty?
260
+
261
+ out = Aptly::runcmd cmd
262
+ Aptly::parse_indented_list out
263
+ end
264
+
265
+ # Shortcut method to publish a snapshot from an Aptly::Snapshot instance.
266
+ def publish args
267
+ Aptly::publish 'snapshot', @name, args
268
+ end
269
+ end
270
+ end