vx-aptly 0.9.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.
Files changed (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/Dockerfile +11 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +29 -0
  7. data/Rakefile +36 -0
  8. data/bin/vx-aptly +4 -0
  9. data/doc/aptly.example +16 -0
  10. data/doc/aptly.upstart +27 -0
  11. data/doc/cloud-files.example +9 -0
  12. data/docker/install.sh +47 -0
  13. data/docker/my_init +57 -0
  14. data/docker/supervisord.conf +17 -0
  15. data/lib/vx/aptly.rb +33 -0
  16. data/lib/vx/aptly/app.rb +194 -0
  17. data/lib/vx/aptly/cli.sh +116 -0
  18. data/lib/vx/aptly/config.ru +3 -0
  19. data/lib/vx/aptly/mixin/capture.rb +37 -0
  20. data/lib/vx/aptly/package.rb +110 -0
  21. data/lib/vx/aptly/public/404.html +153 -0
  22. data/lib/vx/aptly/public/css/animate.css +3158 -0
  23. data/lib/vx/aptly/public/css/bootstrap.min.css +5 -0
  24. data/lib/vx/aptly/public/css/flat-ui.css +6007 -0
  25. data/lib/vx/aptly/public/css/theme.css +131 -0
  26. data/lib/vx/aptly/public/fonts/glyphicons/flat-ui-icons-regular.eot +0 -0
  27. data/lib/vx/aptly/public/fonts/glyphicons/flat-ui-icons-regular.svg +126 -0
  28. data/lib/vx/aptly/public/fonts/glyphicons/flat-ui-icons-regular.ttf +0 -0
  29. data/lib/vx/aptly/public/fonts/glyphicons/flat-ui-icons-regular.woff +0 -0
  30. data/lib/vx/aptly/public/fonts/glyphicons/selection.json +2106 -0
  31. data/lib/vx/aptly/public/fonts/lato/lato-black.eot +0 -0
  32. data/lib/vx/aptly/public/fonts/lato/lato-black.svg +4691 -0
  33. data/lib/vx/aptly/public/fonts/lato/lato-black.ttf +0 -0
  34. data/lib/vx/aptly/public/fonts/lato/lato-black.woff +0 -0
  35. data/lib/vx/aptly/public/fonts/lato/lato-bold.eot +0 -0
  36. data/lib/vx/aptly/public/fonts/lato/lato-bold.svg +5085 -0
  37. data/lib/vx/aptly/public/fonts/lato/lato-bold.ttf +0 -0
  38. data/lib/vx/aptly/public/fonts/lato/lato-bold.woff +0 -0
  39. data/lib/vx/aptly/public/fonts/lato/lato-bolditalic.eot +0 -0
  40. data/lib/vx/aptly/public/fonts/lato/lato-bolditalic.svg +4514 -0
  41. data/lib/vx/aptly/public/fonts/lato/lato-bolditalic.ttf +0 -0
  42. data/lib/vx/aptly/public/fonts/lato/lato-bolditalic.woff +0 -0
  43. data/lib/vx/aptly/public/fonts/lato/lato-italic.eot +0 -0
  44. data/lib/vx/aptly/public/fonts/lato/lato-italic.svg +4514 -0
  45. data/lib/vx/aptly/public/fonts/lato/lato-italic.ttf +0 -0
  46. data/lib/vx/aptly/public/fonts/lato/lato-italic.woff +0 -0
  47. data/lib/vx/aptly/public/fonts/lato/lato-light.eot +0 -0
  48. data/lib/vx/aptly/public/fonts/lato/lato-light.svg +4691 -0
  49. data/lib/vx/aptly/public/fonts/lato/lato-light.ttf +0 -0
  50. data/lib/vx/aptly/public/fonts/lato/lato-light.woff +0 -0
  51. data/lib/vx/aptly/public/fonts/lato/lato-regular.eot +0 -0
  52. data/lib/vx/aptly/public/fonts/lato/lato-regular.svg +4691 -0
  53. data/lib/vx/aptly/public/fonts/lato/lato-regular.ttf +0 -0
  54. data/lib/vx/aptly/public/fonts/lato/lato-regular.woff +0 -0
  55. data/lib/vx/aptly/public/img/favicon.ico +0 -0
  56. data/lib/vx/aptly/public/js/app.js +12 -0
  57. data/lib/vx/aptly/public/js/jquery_ujs.js +446 -0
  58. data/lib/vx/aptly/repo.rb +161 -0
  59. data/lib/vx/aptly/repo_publish.rb +165 -0
  60. data/lib/vx/aptly/version.rb +5 -0
  61. data/lib/vx/aptly/views/index.erb +94 -0
  62. data/lib/vx/aptly/views/layout.erb +54 -0
  63. data/lib/vx/aptly/views/repo_publishes/new.erb +49 -0
  64. data/lib/vx/aptly/views/repos/edit.erb +17 -0
  65. data/lib/vx/aptly/views/repos/errors.erb +5 -0
  66. data/lib/vx/aptly/views/repos/form.erb +26 -0
  67. data/lib/vx/aptly/views/repos/new.erb +17 -0
  68. data/lib/vx/aptly/views/repos/packages.erb +51 -0
  69. data/lib/vx/aptly/views/repos/show.erb +66 -0
  70. data/spec/lib/repo_publish_spec.rb +60 -0
  71. data/spec/spec_helper.rb +13 -0
  72. data/spec/support/aptly.conf +0 -0
  73. data/spec/support/home.rb +39 -0
  74. data/vx-aptly.gemspec +32 -0
  75. metadata +263 -0
@@ -0,0 +1,161 @@
1
+ module Vx
2
+ module Aptly
3
+ class Repo
4
+
5
+ include Mixin::Capture
6
+ extend Mixin::Capture
7
+
8
+ attr_accessor :error, :attributes, :notice
9
+
10
+ def initialize(params = {})
11
+ @attributes = {}
12
+ params.each do |k,v|
13
+ if self.respond_to?(:"#{k}=")
14
+ self.public_send(:"#{k}=", v)
15
+ end
16
+ end
17
+ end
18
+
19
+ def persisted!
20
+ @persisted = true
21
+ end
22
+
23
+ def new_record?
24
+ !@persisted
25
+ end
26
+
27
+ def valid?
28
+ !@error
29
+ end
30
+
31
+ def packages(reload = false)
32
+ @packages = nil if reload
33
+ @packages ||= Package.all(self)
34
+ end
35
+
36
+ %w{ name comment default_component default_distribution number_of_packages}.each do |m|
37
+ define_method :"#{m}=" do |value|
38
+ if value.is_a?(String) && value == ""
39
+ @attributes[m.to_sym] = nil
40
+ else
41
+ @attributes[m.to_sym] = value
42
+ end
43
+ end
44
+
45
+ define_method :"#{m}" do
46
+ value = @attributes[m.to_sym]
47
+ if value == nil
48
+ case m
49
+ when 'default_distribution'
50
+ value = 'ubuntu'
51
+ when 'default_component'
52
+ value = 'main'
53
+ end
54
+ end
55
+ value
56
+ end
57
+ end
58
+
59
+ def create
60
+ line = "aptly repo create"
61
+ line << " -comment=\"#{comment}\"" if comment
62
+ line << " -component=\"#{default_component}\"" if default_component
63
+ line << " -distribution=\"#{default_distribution}\"" if default_distribution
64
+ line << " #{name}" if name
65
+
66
+ begin
67
+ capture line do |re|
68
+ @notice = "The command '#{line}' was successfuly finished with output:\n"
69
+ @notice << re
70
+ end
71
+ persisted!
72
+ rescue AptlyCommandError => e
73
+ @error = e
74
+ end
75
+
76
+ valid?
77
+ end
78
+
79
+ def update
80
+ line = "aptly repo edit"
81
+ line << " -comment=\"#{comment}\"" if comment
82
+ line << " -component=\"#{default_component}\"" if default_component
83
+ line << " -distribution=\"#{default_distribution}\"" if default_distribution
84
+ line << " #{name}" if name
85
+
86
+ begin
87
+ capture line do |re|
88
+ @notice = "The command '#{line}' was successfuly finished with output:\n"
89
+ @notice << re
90
+ end
91
+ rescue AptlyCommandError => e
92
+ @error = e
93
+ end
94
+
95
+ valid?
96
+ end
97
+
98
+ def destroy
99
+ cmd = "aptly repo drop"
100
+ cmd << " #{name}" if name
101
+ capture cmd do |re|
102
+ @notice = "The command '#{cmd}' was successfuly finished with output:\n"
103
+ @notice << re
104
+ end
105
+ end
106
+
107
+ def publishes(reload = false)
108
+ @publishes = nil if reload
109
+ @publishes ||= RepoPublish.for_repo(self)
110
+ end
111
+
112
+ def build_publish(options = {})
113
+ options[:repo_name] = self.name
114
+ options = {
115
+ component: default_component,
116
+ distribution: default_distribution
117
+ }.merge(options)
118
+
119
+ RepoPublish.new(options)
120
+ end
121
+
122
+ class << self
123
+
124
+ def find(name)
125
+ capture "aptly repo show #{name}" do |re|
126
+ repo = new(name: name)
127
+ repo.persisted!
128
+
129
+ re.lines.each do |line|
130
+ key, value = line.split(":").map(&:strip)
131
+ case key
132
+ when 'Comment'
133
+ repo.comment = value
134
+ when 'Default Distribution'
135
+ repo.default_distribution = value
136
+ when 'Default Component'
137
+ repo.default_component = value
138
+ when 'Number of packages'
139
+ repo.number_of_packages = value.to_i
140
+ end
141
+ end
142
+
143
+ repo
144
+ end
145
+ end
146
+
147
+ def all
148
+ capture "aptly repo list" do |re|
149
+ re.lines.inject([]) do |a, line|
150
+ if line =~ / \* \[(.*)\]/
151
+ a << find($1)
152
+ end
153
+ a
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,165 @@
1
+ module Vx
2
+ module Aptly
3
+ class RepoPublish
4
+
5
+ PublishedRepo = Struct.new(:name, :component)
6
+
7
+ include Mixin::Capture
8
+ extend Mixin::Capture
9
+
10
+ attr_reader :attributes, :error, :notice
11
+
12
+ def initialize(params = {})
13
+ @attributes = {}
14
+ params.each do |k,v|
15
+ if self.respond_to?(:"#{k}=")
16
+ self.public_send(:"#{k}=", v)
17
+ end
18
+ end
19
+ end
20
+
21
+ def id
22
+ [prefix, distribution].join("/")
23
+ end
24
+
25
+ def valid?
26
+ !@error
27
+ end
28
+
29
+ def create
30
+ line = "aptly publish repo"
31
+ line << " -architectures=\"#{architectures}\"" if architectures
32
+
33
+ components = repos.map{|i| "" }.join(",") # all components
34
+ line << " -component=\"#{components}\""
35
+
36
+ line << " -distribution=\"#{distribution}\"" if distribution
37
+
38
+ repos.each do |repo|
39
+ line << " #{repo.name}"
40
+ end
41
+
42
+ if repos.any? && prefix
43
+ line << " #{prefix}"
44
+ end
45
+
46
+ begin
47
+ capture line do |re|
48
+ @notice = "The command '#{line}' was successfuly finished with output:\n"
49
+ @notice << re
50
+ end
51
+ rescue AptlyCommandError => e
52
+ @error = e
53
+ end
54
+
55
+ valid?
56
+ end
57
+
58
+ def update
59
+ begin
60
+ line = update_command_line
61
+ capture line do |re|
62
+ @notice = "The command '#{line}' was successfuly finished with output:\n"
63
+ @notice << re
64
+ end
65
+ rescue AptlyCommandError => e
66
+ @error = e
67
+ end
68
+
69
+ valid?
70
+ end
71
+
72
+ def update_command_line
73
+ line = "aptly publish update"
74
+ line << " -architectures=\"#{architectures}\"" if architectures
75
+ line << " #{distribution}" if distribution
76
+ line << " #{prefix}" if distribution && prefix
77
+ line
78
+ end
79
+
80
+ def destroy
81
+ line = "aptly publish drop "
82
+ line << " -architectures=\"#{architectures}\"" if architectures
83
+ line << " #{distribution}" if distribution
84
+ line << " #{prefix}" if distribution && prefix
85
+ begin
86
+ capture line do |re|
87
+ @notice = "The command '#{line}' was successfuly finished with output:\n"
88
+ @notice << re
89
+ end
90
+ rescue AptlyCommandError => e
91
+ @error = e
92
+ end
93
+ valid?
94
+ end
95
+
96
+ %w{ prefix component architectures distribution }.each do |m|
97
+ define_method :"#{m}=" do |value|
98
+ if value.to_s.strip == ''
99
+ value = nil
100
+ end
101
+ @attributes[m.to_sym] = value
102
+ end
103
+
104
+ define_method :"#{m}" do
105
+ @attributes[m.to_sym]
106
+ end
107
+ end
108
+
109
+ def repos=(val)
110
+ @attributes[:repos] = []
111
+ if val.is_a?(Array)
112
+ val.each do |repo|
113
+ if repo.is_a?(Hash)
114
+ @attributes[:repos].push PublishedRepo.new(repo[:name], repo[:component])
115
+ else
116
+ @attributes[:repos].push PublishedRepo.new(repo.to_s)
117
+ end
118
+ end
119
+ end
120
+ @attributes[:repos]
121
+ end
122
+
123
+ def repos
124
+ @attributes[:repos] ||= []
125
+ @attributes[:repos]
126
+ end
127
+
128
+ class << self
129
+ def all(options = {})
130
+ capture 'aptly publish list' do |re|
131
+ re.lines.inject([]) do |a,line|
132
+ if line =~ /\* (.+)\/(.+) \[(.+)\] publishes (.*)$/
133
+ it = new(prefix: $1, distribution: $2, architectures: $3)
134
+ repos = $4
135
+ published_repos = []
136
+
137
+ repos.split(",").map(&:strip).map do |repo|
138
+ if repo =~ /\{(.*): \[(.*)\]/
139
+ published_repos << { name: $2, component: $1 }
140
+ end
141
+ end
142
+
143
+ it.repos = published_repos
144
+
145
+ a << it
146
+ end
147
+ a
148
+ end
149
+ end
150
+ end
151
+
152
+ def for_repo(repo)
153
+ all.select{|pub| pub.repos.map(&:name).include?(repo.name) }
154
+ end
155
+
156
+ def find(id)
157
+ if id.split("/").size == 1
158
+ id = "./#{id}"
159
+ end
160
+ all.find{|pub| pub.id == id } or raise(PublishNotFoundError, "The publish with id #{id} was not found")
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,5 @@
1
+ module Vx
2
+ module Aptly
3
+ VERSION = "0.9.0"
4
+ end
5
+ end
@@ -0,0 +1,94 @@
1
+ <% @menu = [['Dashboard', '/', true]] %>
2
+
3
+ <% if @repos.any? %>
4
+ <div class="panel panel-default">
5
+ <div class="panel-heading">
6
+ <div class="pull-right">
7
+ <a href="/repos/new" class="btn btn-default btn-sm">
8
+ <%= ico 'plus' %>
9
+ Add a repo
10
+ </a>
11
+ </div>
12
+ <h6>Repos</h6>
13
+ </div>
14
+ <table class="table table-hover">
15
+ <% for repo in @repos %>
16
+ <tr>
17
+ <td>
18
+ <a href="/repos/<%= repo.name %>">
19
+ <small>
20
+ <%= repo.name %> (<%= repo.number_of_packages %>)
21
+ </small>
22
+ </a>
23
+ </td>
24
+ <td><small class="text-muted"><%= repo.comment %></small></td>
25
+ <td><small class=""><%= repo.default_distribution %></small></td>
26
+ <td><small class=""><%= repo.default_component %></small></td>
27
+ </tr>
28
+ <% end %>
29
+ </table>
30
+ </div>
31
+ <% else %>
32
+ <div class="jumbotron">
33
+ <p class="lead">You have no repositories</p>
34
+ <p><a class="btn btn-lg btn-success" href="/repos/new" role="button">
35
+ <%= ico 'plus' %>
36
+ Create one
37
+ </a></p>
38
+ </div>
39
+ <% end %>
40
+
41
+ <% if @pubs.any? %>
42
+ <div class="panel panel-default">
43
+ <div class="panel-heading">
44
+ <div class="pull-right">
45
+ <a href="/repo/publishes/new" class="btn btn-default btn-sm">
46
+ <%= ico 'plus' %>
47
+ Add a publish
48
+ </a>
49
+ </div>
50
+ <h6>Published Repos</h6>
51
+ </div>
52
+ <table class="table table-hover table-btn-group">
53
+ <% for pub in @pubs %>
54
+ <tr>
55
+ <td>
56
+ <small><%= pub.id %></small>
57
+ </td>
58
+ <td>
59
+ <small><%= pub.architectures %></small>
60
+ </td>
61
+ <td>
62
+ <% for repo in pub.repos %>
63
+ <a href="/repos/<%= repo.name %>" style="display:block">
64
+ <small class=""><%= repo.name %> (<%= repo.component %>)</small>
65
+ </a>
66
+ <% end %>
67
+ </td>
68
+ <td>
69
+ <div class="btn-group">
70
+ <a class="btn btn-xs btn-primary" href="/repo/publishes/<%= pub.id %>" data-method="patch" data-confirm="Are you sure?">
71
+ <%= ico 'upload' %>
72
+ Update
73
+ </a>
74
+ <a class="btn btn-xs btn-danger" href="/repo/publishes/<%= pub.id %>" data-method="delete" data-confirm="Are you sure?">
75
+ <%= ico 'cross' %>
76
+ Remove
77
+ </a>
78
+ </div>
79
+ </td>
80
+ </tr>
81
+ <% end %>
82
+ </table>
83
+ </div>
84
+ <% else %>
85
+ <% if @repos.any? %>
86
+ <div class="jumbotron">
87
+ <p class="lead">You have no published repos</p>
88
+ <p><a class="btn btn-lg btn-success" href="/repo/publishes/new" role="button">
89
+ <%= ico 'plus' %>
90
+ Create one
91
+ </a></p>
92
+ </div>
93
+ <% end %>
94
+ <% end %>
@@ -0,0 +1,54 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1">
7
+
8
+ <link rel="stylesheet" href="/css/bootstrap.min.css">
9
+ <link rel="stylesheet" href="/css/flat-ui.css">
10
+ <link rel="stylesheet" href="/css/animate.css">
11
+ <link rel="stylesheet" href="/css/theme.css">
12
+
13
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
14
+ <script src="/js/jquery_ujs.js"></script>
15
+ <script src="/js/app.js"></script>
16
+
17
+ <link rel="shortcut icon" href="img/favicon.ico">
18
+
19
+ <title>Aptly Web</title>
20
+ </head>
21
+
22
+ <body>
23
+
24
+ <a href="https://github.com/vexor/vx-aptly" target="_blank"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/a6677b08c955af8400f44c6298f40e7d19cc5b2d/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f677261795f3664366436642e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png"></a>
25
+
26
+ <div class="container">
27
+ <div class="header">
28
+ <% if @menu %>
29
+ <ul class="nav nav-pills " role="tablist">
30
+ <% for name, url, active in @menu %>
31
+ <li role="presentation" class="<%= 'active' if active %>"><a href="<%= url %>"><%= name %></a></li>
32
+ <% end %>
33
+ </ul>
34
+ <% end %>
35
+ </div>
36
+
37
+ <% if flash[:notice] %>
38
+ <pre class="notice"><%= flash[:notice] %></pre>
39
+ <% end %>
40
+ <% if flash[:error] %>
41
+ <pre class="error"><%= flash[:error] %></pre>
42
+ <% end %>
43
+
44
+ <%= yield %>
45
+ <!--
46
+ <div class="footer">
47
+ <p>&copy; Vexor 2014</p>
48
+ </div>
49
+ -->
50
+
51
+ </div> <!-- /container -->
52
+ </body>
53
+ </html>
54
+