aptly 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.
@@ -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