Module: Aptly

Extended by:
Aptly
Included in:
Aptly
Defined in:
lib/aptly.rb,
lib/aptly/repo.rb,
lib/aptly/mutex.rb,
lib/aptly/mirror.rb,
lib/aptly/publish.rb,
lib/aptly/version.rb,
lib/aptly/snapshot.rb

Defined Under Namespace

Classes: Mirror, Mutex, PublishedResource, Repo, Snapshot

Constant Summary collapse

VERSION =
'0.1.0'

Instance Method Summary collapse

Instance Method Details

#create_empty_snapshot(name) ⇒ Object

Shortcut method to create an empty snapshot



60
61
62
# File 'lib/aptly/snapshot.rb', line 60

def create_empty_snapshot name
  create_snapshot name, 'empty'
end

#create_mirror(name, baseurl, dist, kwargs = {}) ⇒ Object

Creates a new mirror in aptly. This simply creates the necessary records in leveldb and doesn’t do any heavy lifting.

Parameters:

name

The name of the new repository

baseurl

The URL to the repository content

dist

The distribution (e.g. precise, quantal)

components

The repository components (e.g. main, stable)

archlist

A list of architecture types to mirror

ignoresigs

Ignore package signature mismatches

source

Optionally mirror in source packages

Returns:

An Aptly::Mirror object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/aptly/mirror.rb', line 26

def create_mirror(
  name,
  baseurl,
  dist,
  kwargs={}
)
  components = kwargs.arg :components, []
  archlist = kwargs.arg :archlist, []
  ignoresigs = kwargs.arg :ignoresigs, false
  source = kwargs.arg :source, false

  if list_mirrors.include? name
    raise AptlyError.new "Mirror '#{name}' already exists"
  end

  if components.length < 1
    raise AptlyError.new "1 or more components are required"
  end

  cmd = 'aptly mirror create'
  cmd += " -architectures #{archlist.join(',')}" if !archlist.empty?
  cmd += ' -ignore-signatures' if ignoresigs
  cmd += ' -with-sources' if source
  cmd += " #{name.quote} #{baseurl.quote} #{dist.quote}"
  cmd += " #{components.join(' ')}"

  runcmd cmd
  return Mirror.new name
end

#create_mirror_snapshot(name, mirror_name) ⇒ Object

Shortcut method to create a snapshot from a mirror



50
51
52
# File 'lib/aptly/snapshot.rb', line 50

def create_mirror_snapshot name, mirror_name
  create_snapshot name, 'mirror', :resource_name => mirror_name
end

#create_repo(name, kwargs = {}) ⇒ Object

Creates a new repository in aptly

Parameters:

name

The name to use for the new repository

dist

The distribution used during publishing

comment

A comment describing the repository

component

The component used during publishing

Returns:

An Aptly::Repo object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/aptly/repo.rb', line 19

def create_repo name, kwargs={}
  dist = kwargs.arg :dist, ''
  comment = kwargs.arg :comment, ''
  component = kwargs.arg :component, 'main'
  if list_repos.include? name
    raise AptlyError.new("Repo '#{name}' already exists")
  end

  cmd = "aptly repo create"
  cmd += " -comment=#{comment.quote}" if !comment.empty?
  cmd += " -distribution=#{dist.quote}" if !dist.empty?
  cmd += " #{name}"

  runcmd cmd
  return Repo.new name
end

#create_repo_snapshot(name, repo_name) ⇒ Object

Shortcut method to create a snapshot from a repo



55
56
57
# File 'lib/aptly/snapshot.rb', line 55

def create_repo_snapshot name, repo_name
  create_snapshot name, 'repo', :resource_name => repo_name
end

#list_mirrorsObject

Returns a list of existing mirrors in aptly

Returns

An array of mirror names



61
62
63
64
# File 'lib/aptly/mirror.rb', line 61

def list_mirrors
  out = runcmd 'aptly mirror list'
  parse_list out.lines
end

#list_publishedObject

List existing published resources.

Returns

A hash of published resource information. The outer hash key is the published resource path, and its value is the resource metadata.



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/aptly/publish.rb', line 73

def list_published
  res = Hash.new
  out = runcmd 'aptly publish list'
  out.lines.each do |line|
    if line.start_with? '  * '
      resource = {}
      parts = line[3..-1].split(/\[|\]|\(|\)/)
      resource['path'] = parts[0].strip
      resource['component'] = parts[1].strip
      resource['archlist'] = parts[3].split(', ')
      resource['from_name'] = parts[5].strip
      if parts[6].include? 'Snapshot'
        resource['from_type'] = 'snapshot'
      elsif parts[6].include? 'Repo'
        resource['from_type'] = 'repo'
      else
        next
      end
      dist = line.split.last
      res[dist] = resource
    end
  end
  res
end

#list_reposObject

Return a list of existing repositories

Returns

An array of strings representing repository names



41
42
43
44
# File 'lib/aptly/repo.rb', line 41

def list_repos
  out = runcmd 'aptly repo list'
  parse_list out.lines
end

#list_snapshotsObject

List existing snapshots

Returns:

A list of snapshot names



69
70
71
72
# File 'lib/aptly/snapshot.rb', line 69

def list_snapshots
  out = runcmd 'aptly snapshot list'
  parse_list out.lines
end

#merge_snapshots(dest, kwargs = {}) ⇒ Object

Merge snapshots into a single snapshot. This will create a new snapshot containing packages from all source snapshots. By default, packages with the same name-architecture pair are merged from right-over-left, meaning packages in the last source snapshot may overwrite the same packages in the first source snapshot if their name-architecture pairs match.

Parameters:

dest

The destination snapshot name (will be created)

sources

The names of source repositories. The order in which these are passed matters unless ‘-latest` is not passed.

latest

When true, only the latest of each package will be copied into the new snapshot, following a “latest wins” approach.

Returns:

An Aptly::Snapshot object for the new snapshot



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/aptly/snapshot.rb', line 107

def merge_snapshots dest, kwargs={}
  sources = kwargs.arg :sources, []
  latest = kwargs.arg :latest, false

  if sources.length == 0
    raise AptlyError.new '1 or more sources are required'
  end

  if list_snapshots.include? dest
    raise AptlyError.new "Snapshot '#{dest}' exists"
  end

  cmd = 'aptly snapshot merge'
  cmd += ' -latest' if latest
  cmd += " #{dest.quote}"
  cmd += " #{sources.join(' ')}"

  runcmd cmd
  Aptly::Snapshot.new dest
end

#mirror_info(name) ⇒ Object

Retrieves information about a mirror

Parameters:

name

The name of the mirror to retrieve info for

Returns:

A hash of mirror information



75
76
77
78
# File 'lib/aptly/mirror.rb', line 75

def mirror_info name
  out = runcmd "aptly mirror show #{name.quote}"
  parse_info out.lines
end

#multi(items, key) ⇒ Object



76
77
78
# File 'lib/aptly.rb', line 76

def multi items, key
  items[key] = items[key].split(' ') if items.has_key? key
end

#parse_indented_list(lines) ⇒ Object

Parses aptly output of double-space indented lists

Parameters:

lines

Output lines from an aptly list command

Result:

An array of items



95
96
97
98
99
100
101
# File 'lib/aptly.rb', line 95

def parse_indented_list lines
  items = Array.new
  lines.each do |line|
    items << line.strip if line.start_with? '  '
  end
  items
end

#parse_info(lines) ⇒ Object

Parses the output of aptly show commands.

Parameters:

lines

An array of strings of aptly output

Returns:

A hash of information



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/aptly.rb', line 69

def parse_info lines
  items = Hash.new
  lines.reject{|l| l.empty?}.each do |line|
    parts = line.split(/:\s/, 2)
    items[parts[0]] = parts[1].strip if parts.length == 2
  end

  def multi items, key
    items[key] = items[key].split(' ') if items.has_key? key
  end

  multi items, 'Components'
  multi items, 'Architectures'

  items
end

#parse_list(lines) ⇒ Object

Parses the output lines of aptly listing commands

Parameters:

lines

An array of lines of string output from aptly list commands

Returns:

An array of items



49
50
51
52
53
54
55
56
57
58
# File 'lib/aptly.rb', line 49

def parse_list lines
  items = Array.new
  lines.each do |line|
    if line.start_with?(' * ')
      parts = line.split(/\[|\]/, 3)
      items << parts[1] if parts.length == 3
    end
  end
  items
end

#publish(type, name, kwargs = {}) ⇒ Object

Publish a snapshot or repo resource.

Parameters:

type

The type of resource to publish. ‘snapshot’ and ‘repo’ supported.

name

The name of the resource to publish.

prefix

An optional prefix to publish to.

component

The component to publish to. If empty, aptly will attempt to guess from the source, or use ‘main’ as the default.

dist

The distribution name. If empty, aptly will try to guess.

gpg_key

The gpg key to sign the repository. Uses default if not specified.

keyring

GPG keyring to use

label

An optional label to give the published resource

origin

The value of the ‘Origin’ field

secret_keyring

GPG secret keyring to use

sign

When false, don’t sign Release files. Defaults to true.



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/aptly/publish.rb', line 31

def publish(
  type,
  name,
  kwargs={}
)
  prefix = kwargs.arg :prefix, ''
  component = kwargs.arg :component, ''
  dist = kwargs.arg :dist, ''
  gpg_key = kwargs.arg :gpg_key, ''
  keyring = kwargs.arg :keyring, ''
  label = kwargs.arg :label, ''
  origin = kwargs.arg :origin, ''
  secret_keyring = kwargs.arg :secret_keyring, ''
  sign = kwargs.arg :sign, true

  if type != 'repo' && type != 'snapshot'
    raise AptlyError "Invalid publish type: #{type}"
  end

  cmd = "aptly publish #{type}"
  cmd += ' -skip-signing' if !sign
  cmd += " -component #{component.quote}" if !component.empty?
  cmd += " -distribution #{dist.quote}" if !dist.empty?
  cmd += " -gpg-key #{gpg_key.quote}" if !gpg_key.empty?
  cmd += " -keyring #{keyring.quote}" if !keyring.empty?
  cmd += " -label #{label.quote}" if !label.empty?
  cmd += " -origin #{origin.quote}" if !origin.empty?
  cmd += " #{name.quote}"
  cmd += " #{prefix.quote}" if !prefix.empty?
  if !secret_keyring.empty?
    cmd += " -secret-keyring #{secret_keyring.quote}"
  end

  runcmd cmd
end

#repo_info(name) ⇒ Object

Retrieve information about a repository

Parameters:

name

The name of the repository to retrieve information for

Returns:

A hash of repository information



55
56
57
58
# File 'lib/aptly/repo.rb', line 55

def repo_info name
  out = runcmd "aptly repo show #{name.quote}"
  parse_info out.lines
end

#runcmd(cmd) ⇒ Object

runcmd handles running arbitrary commands. It is intended to run aptly- specific commands, and as such, it uses a mutex to take gurantee consistency and avoid multiple processes modifying aptly simultaneously.

Parameters:

cmd

A string holding the command to run

Returns:

The content of stdout



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/aptly.rb', line 24

def runcmd cmd
  Mutex.lock
  at_exit { Mutex.unlock }

  out = %x(#{cmd} 2>&1)
  res = $?.exitstatus

  Mutex.unlock

  if res != 0
    raise AptlyError.new "aptly: command failed: #{cmd}", out
  end

  return out
end

#snapshot_info(name) ⇒ Object

Retrieves information about a snapshot

Parameters:

name

The name of the snapshot to gather information about

Returns:

A hash of snapshot information



83
84
85
86
# File 'lib/aptly/snapshot.rb', line 83

def snapshot_info name
  out = runcmd "aptly snapshot show #{name.quote}"
  parse_info out.lines
end