pandler 0.0.1

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 (37) hide show
  1. data/.gitignore +23 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +47 -0
  5. data/Rakefile +10 -0
  6. data/Vagrantfile +33 -0
  7. data/bin/pandle +8 -0
  8. data/etc/yum/pandler.py +52 -0
  9. data/lib/pandler.rb +8 -0
  10. data/lib/pandler/chroot.rb +229 -0
  11. data/lib/pandler/cli.rb +40 -0
  12. data/lib/pandler/version.rb +3 -0
  13. data/lib/pandler/yumfile.rb +26 -0
  14. data/lib/pandler/yumrepo.rb +240 -0
  15. data/pandler.gemspec +24 -0
  16. data/spec/pandler/chroot_spec.rb +93 -0
  17. data/spec/pandler/cli_spec.rb +20 -0
  18. data/spec/pandler/yumfile_spec.rb +20 -0
  19. data/spec/pandler/yumrepo_spec.rb +152 -0
  20. data/spec/pandler_spec.rb +8 -0
  21. data/spec/resources/yumrepo/pandler-test-0.0.1-1.x86_64.rpm +0 -0
  22. data/spec/resources/yumrepo/pandler-test-a-0.0.1-1.x86_64.rpm +0 -0
  23. data/spec/resources/yumrepo/pandler-test-a-0.0.2-1.x86_64.rpm +0 -0
  24. data/spec/resources/yumrepo/pandler-test-dep-a-0.0.1-1.x86_64.rpm +0 -0
  25. data/spec/resources/yumrepo/pandler-test-dep-b-0.0.1-1.x86_64.rpm +0 -0
  26. data/spec/resources/yumrepo/pandler-test-dep-required-0.0.1-1.x86_64.rpm +0 -0
  27. data/spec/resources/yumrepo/pandler-test-dep-required-required-0.0.1-1.x86_64.rpm +0 -0
  28. data/spec/resources/yumrepo/repodata/09267893997a9b34726567132f642093ebd2a4b5e65096a6562efc3a29106723-other.xml.gz +0 -0
  29. data/spec/resources/yumrepo/repodata/596e9069dad80db19e7ba4c36b3df1e52583231b95bfa61186408c77520a213a-primary.xml.gz +0 -0
  30. data/spec/resources/yumrepo/repodata/7dd30f881bb1b1cbd723a5fa9d996b96805e25015b56140c99a444bf248c4260-other.sqlite.bz2 +0 -0
  31. data/spec/resources/yumrepo/repodata/8e6f832a8605163914b5aaf46e42daeaad10f9785d202c6c99c9d903354b3194-filelists.xml.gz +0 -0
  32. data/spec/resources/yumrepo/repodata/a810cd5676bb578a196231dae1f37179241630f6745a3d33691279ff61bfe175-primary.sqlite.bz2 +0 -0
  33. data/spec/resources/yumrepo/repodata/ad696c5b02dadaef085b16712ce0464ae0d4c102b3ccf1ce0f14e371a119463a-filelists.sqlite.bz2 +0 -0
  34. data/spec/resources/yumrepo/repodata/repomd.xml +55 -0
  35. data/spec/spec_helper.rb +82 -0
  36. data/vagrant_file.sh +30 -0
  37. metadata +156 -0
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .*.swp
19
+ bin/*
20
+ !bin/pandle
21
+ .vagrant
22
+ vendor/bundle
23
+ spec/resources/repo
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pandler.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Ryosuke IWANAGA
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,47 @@
1
+ # Pandler
2
+ Manage your packages with chroot.
3
+
4
+ Pandler(= Package + Bundler) helps managing rpm/yum packages. Using `Yumfile` and `Yumfile.lock`, Pandler automatically creates a locked chroot environment.
5
+
6
+ ## Installation
7
+
8
+ *Currently Pandler support only root user usage because of `mount`. You should install and run as root user.*
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'pandler'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install pandler
21
+
22
+ ## Usage
23
+
24
+ Write `Yumfile`.
25
+
26
+ repo "base", "http://vault.centos.org/6.2/os/x86_64/"
27
+
28
+ rpm "basesystem"
29
+ rpm ""
30
+
31
+ Run `pandle install`.
32
+
33
+ # pandle install
34
+ # pandle list
35
+
36
+ Then, you can execute any command in the chroot environment.
37
+
38
+ # pandle exec pwd
39
+ /
40
+
41
+ ## Contributing
42
+
43
+ 1. Fork it
44
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
45
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
46
+ 4. Push to the branch (`git push origin my-new-feature`)
47
+ 5. Create new Pull Request
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :default => [:spec]
4
+ begin
5
+ require 'rspec/core/rake_task'
6
+ RSpec::Core::RakeTask.new(:spec) do |spec|
7
+ spec.rspec_opts = %w[-cfs -r ./spec/spec_helper.rb]
8
+ end
9
+ rescue LoadError => e
10
+ end
@@ -0,0 +1,33 @@
1
+ Vagrant.configure("2") do |vagrant|
2
+ define_list = [
3
+ {
4
+ :name => :centos,
5
+ :box => "Berkshelf-CentOS-6.3-x86_64-minimal",
6
+ :box_url => "http://dl.dropbox.com/u/31081437/Berkshelf-CentOS-6.3-x86_64-minimal.box",
7
+ :pkgm => :yum,
8
+ },
9
+ # {
10
+ # :name => :ubuntu,
11
+ # :box => "precise64",
12
+ # :box_url => "http://files.vagrantup.com/precise64.box",
13
+ # :pkgm => :apt,
14
+ # },
15
+ ]
16
+
17
+ vagrant.vm.provider :virtualbox do |v|
18
+ v.customize ["modifyvm", :id, "--memory", 256]
19
+ v.customize ["modifyvm", :id, "--cpus", 4]
20
+ end
21
+
22
+ define_list.each_with_index do |define, i|
23
+ vagrant.vm.define define[:name] do |config|
24
+ config.vm.box = define[:box]
25
+ config.vm.box_url = define[:box_url]
26
+
27
+ config.vm.hostname = define[:name].to_s
28
+ config.vm.network :private_network, ip: "192.168.50.#{i + 10}"
29
+
30
+ config.vm.provision :shell, :path => "vagrant_file.sh"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path("../../lib", __FILE__)
4
+
5
+ require "pandler"
6
+ require "pandler/cli"
7
+
8
+ Pandler::CLI.start(ARGV)
@@ -0,0 +1,52 @@
1
+ from yum.plugins import PluginYumExit, TYPE_INTERACTIVE
2
+ import sys
3
+ import pprint
4
+
5
+ requires_api_version = '2.1'
6
+ plugin_type = (TYPE_INTERACTIVE,)
7
+
8
+ def config_hook(conduit):
9
+ parser = conduit.getOptParser()
10
+ if hasattr(parser, 'plugin_option_group'):
11
+ parser = parser.plugin_option_group
12
+
13
+ def postresolve_hook(conduit):
14
+ persistdir = conduit._base._conf.persistdir
15
+ pkgs = [x[0] for x in conduit.getTsInfo().pkgdict.values()]
16
+
17
+ file = open(persistdir+"/pandler.log", "w")
18
+ for pkg in pkgs:
19
+ relatedto_list = [x[0] for x in set(pkg.relatedto)]
20
+
21
+ dic = {
22
+ "package" : __pkg_to_s(pkg),
23
+ "name" : pkg.name,
24
+ "version" : pkg.version,
25
+ "release" : pkg.release,
26
+ "arch" : pkg.arch,
27
+ }
28
+ if len(relatedto_list) == 0:
29
+ ltsv = u"\t".join(k + u":" + v for k, v in dic.iteritems())
30
+ # print(ltsv)
31
+ file.write(ltsv + "\n")
32
+ else:
33
+ for relatedto in relatedto_list:
34
+ dic["relatedto"] = __pkg_to_s(relatedto)
35
+ ltsv = u"\t".join(k + u":" + v for k, v in dic.iteritems())
36
+ # print(ltsv)
37
+ file.write(ltsv + "\n")
38
+
39
+ file.close()
40
+
41
+ def postdownload_hook(conduit):
42
+ opts, commands = conduit.getCmdLine()
43
+ # Don't die on errors, or we'll never see them.
44
+ if not conduit.getErrors():
45
+ sys.exit(0)
46
+
47
+ def __pkg_to_s(pkg):
48
+ name = pkg.name
49
+ version = pkg.version
50
+ release = pkg.release
51
+ arch = pkg.arch
52
+ return "%(name)s-%(version)s-%(release)s.%(arch)s" % locals()
@@ -0,0 +1,8 @@
1
+ require "pandler/version"
2
+ require "pandler/yumfile"
3
+ require "pandler/chroot"
4
+ require "pandler/yumrepo"
5
+
6
+ module Pandler
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,229 @@
1
+ require "etc"
2
+ require "open3"
3
+
4
+ class Pandler::Chroot
5
+ attr_reader :base_dir, :root_dir, :yumrepo, :mounts
6
+
7
+ def initialize(args = {})
8
+ @base_dir = args[:base_dir] || File.expand_path("pandler")
9
+ @root_dir = args[:root_dir] || File.join(base_dir, "root")
10
+ @yumrepo = args[:yumrepo] || "file://" + File.join(base_dir, "yumrepo")
11
+
12
+ @mounts = [
13
+ { :type => 'proc', :path => '/proc' },
14
+ { :type => 'sysfs', :path => '/sys' },
15
+ { :type => 'tmpfs', :path => '/dev/shm' },
16
+ { :type => 'devpts', :path => '/dev/pts',
17
+ :options => "gid=#{Etc.getgrnam("tty").gid},mode=0620,ptmxmode=0666,newinstance" },
18
+ ]
19
+ end
20
+
21
+ def real_path(path)
22
+ File.join(root_dir, path)
23
+ end
24
+
25
+ def init
26
+ setup_dirs
27
+ setup_files
28
+ setup_devs
29
+ mount_all
30
+ true
31
+ end
32
+
33
+ def install(*pkgs)
34
+ yum_install(*pkgs)
35
+ rpm_erase_exclude(*pkgs)
36
+ end
37
+
38
+ def installed_pkgs
39
+ rpm_qa
40
+ end
41
+
42
+ def execute(*cmd)
43
+ chroot_run_cmd(*cmd)
44
+ end
45
+
46
+ def clean
47
+ umount_all
48
+ FileUtils.remove_entry_secure root_dir
49
+ end
50
+
51
+ def list
52
+ rpm_qa
53
+ end
54
+
55
+ private
56
+
57
+ def yum_install(*pkgs)
58
+ cmd = ["yum", "--installroot", root_dir, "install"] + pkgs
59
+ run_cmd(*cmd)
60
+ end
61
+
62
+ def rpm_erase_exclude(*pkgs)
63
+ remove_pkgs = gratuitous_pkgs(*pkgs)
64
+ if remove_pkgs.size > 0
65
+ cmd = ["rpm", "--root", root_dir, "--erase"] + remove_pkgs
66
+ run_cmd(*cmd)
67
+ end
68
+ end
69
+
70
+ def gratuitous_pkgs(*pkgs)
71
+ rpm_qa - pkgs
72
+ end
73
+
74
+ def rpm_qa
75
+ run_cmd_capture_stdout("rpm", "--root", root_dir, "-qa").sort
76
+ end
77
+
78
+ def run_cmd(*cmd)
79
+ ret = Kernel.system(*cmd)
80
+ raise "command failed(ret: #{ret}) '#{cmd.join(" ")}'" unless ret
81
+ end
82
+
83
+ def chroot_run_cmd(*cmd)
84
+ run_cmd("chroot", root_dir, *cmd)
85
+ end
86
+
87
+ def run_cmd_capture_stdout(*cmd)
88
+ Open3.popen3(*cmd) do |stdin, stdout, stderr|
89
+ stdin.close
90
+ stdout.readlines.map { |l| l.chomp }
91
+ end
92
+ end
93
+
94
+ def write_file(path, content)
95
+ open(real_path(path), "w") { |f| f.write content }
96
+ end
97
+
98
+ def mount_all
99
+ @mounts.each do |entry|
100
+ mount(entry)
101
+ end
102
+ end
103
+
104
+ def mount(entry)
105
+ unless mounted?(entry)
106
+ cmd = ["mount", "-t", entry[:type]]
107
+ cmd.concat ["-o", entry[:options]] if entry.has_key?(:options)
108
+ cmd.concat ["pandler_mount", real_path(entry[:path])]
109
+ run_cmd(*cmd)
110
+ end
111
+ end
112
+
113
+ def mounted?(entry)
114
+ `mount`.split("\n").map { |line| line.split[2] }.include?(real_path(entry[:path]))
115
+ end
116
+
117
+ def umount_all
118
+ @mounts.each do |entry|
119
+ umount(entry)
120
+ end
121
+ end
122
+
123
+ def umount(entry)
124
+ if mounted?(entry)
125
+ cmd = ["umount", "-l", real_path(entry[:path])]
126
+ run_cmd(*cmd)
127
+ end
128
+ end
129
+
130
+ def setup_dirs
131
+ FileUtils.mkdir_p root_dir
132
+ dirs = [
133
+ '/var/lib/rpm',
134
+ '/var/lib/yum',
135
+ '/var/lib/dbus',
136
+ '/var/log',
137
+ '/var/lock/rpm',
138
+ '/var/cache/yum',
139
+ '/etc/rpm',
140
+ '/tmp',
141
+ '/tmp/ccache',
142
+ '/var/tmp',
143
+ '/etc/yum.repos.d',
144
+ '/etc/yum',
145
+ '/proc',
146
+ '/sys',
147
+ ]
148
+ dirs.each do |dir|
149
+ FileUtils.mkdir_p real_path(dir)
150
+ end
151
+ end
152
+
153
+ def setup_files
154
+ files = [
155
+ '/etc/mtab',
156
+ '/etc/fstab',
157
+ '/var/log/yum.log',
158
+ ]
159
+ files.each do |file|
160
+ FileUtils.touch real_path(file)
161
+ end
162
+
163
+ write_file("/etc/yum/yum.conf", yum_conf)
164
+ FileUtils.ln_s("yum/yum.conf", real_path("/etc/yum.conf"), { :force => true })
165
+ FileUtils.cp("/etc/resolv.conf", real_path("/etc/resolv.conf"))
166
+ FileUtils.cp("/etc/hosts", real_path("/etc/hosts"))
167
+ end
168
+
169
+ def setup_devs
170
+ FileUtils.mkdir_p real_path("/dev/pts")
171
+ FileUtils.mkdir_p real_path("/dev/shm")
172
+
173
+ python_code = <<-PYTHON
174
+ import sys, os, os.path, stat
175
+ devFiles = [
176
+ (stat.S_IFCHR | 0666, os.makedev(1, 3), "#{real_path("/dev/null")}"),
177
+ (stat.S_IFCHR | 0666, os.makedev(1, 7), "#{real_path("/dev/full")}"),
178
+ (stat.S_IFCHR | 0666, os.makedev(1, 5), "#{real_path("/dev/zero")}"),
179
+ (stat.S_IFCHR | 0666, os.makedev(1, 8), "#{real_path("/dev/random")}"),
180
+ (stat.S_IFCHR | 0444, os.makedev(1, 9), "#{real_path("/dev/urandom")}"),
181
+ (stat.S_IFCHR | 0666, os.makedev(5, 0), "#{real_path("/dev/tty")}"),
182
+ (stat.S_IFCHR | 0600, os.makedev(5, 1), "#{real_path("/dev/console")}"),
183
+ # (stat.S_IFCHR | 0666, os.makedev(5, 2), "#{real_path("/dev/ptmx")}"),
184
+ ]
185
+ for i in devFiles:
186
+ if os.path.exists(i[2]):
187
+ continue
188
+ else:
189
+ os.mknod(i[2], i[0], i[1])
190
+ sys.exit(0)
191
+ PYTHON
192
+ run_cmd("python", "-c", python_code)
193
+
194
+ FileUtils.symlink("/proc/self/fd/0", real_path("/dev/stdin"), { :force => true })
195
+ FileUtils.symlink("/proc/self/fd/1", real_path("/dev/stdout"), { :force => true })
196
+ FileUtils.symlink("/proc/self/fd/2", real_path("/dev/stderr"), { :force => true })
197
+
198
+ FileUtils.chown(Etc.getpwnam("root").uid, Etc.getgrnam("tty").gid, real_path("/dev/tty"))
199
+ # FileUtils.chown(Etc.getpwnam("root").uid, Etc.getgrnam("tty").gid, real_path("/dev/ptmx"))
200
+
201
+ unless File.exists? real_path("/dev/fd")
202
+ FileUtils.symlink("/proc/self/fd", real_path("/dev/fd"), { :force => true })
203
+ end
204
+ FileUtils.symlink("pts/ptmx", real_path("/dev/ptmx"), { :force => true })
205
+ end
206
+
207
+ def yum_conf
208
+ content = <<-EOF
209
+ [main]
210
+ cachedir=/var/cache/yum
211
+ debuglevel=1
212
+ reposdir=/dev/null
213
+ logfile=/var/log/yum.log
214
+ retries=20
215
+ obsoletes=1
216
+ gpgcheck=0
217
+ assumeyes=1
218
+ syslog_ident=pandler
219
+ syslog_device=
220
+ plugins=0
221
+
222
+ [pandler]
223
+ name=Pandler
224
+ enabled=1
225
+ baseurl=#{yumrepo}
226
+ EOF
227
+ content
228
+ end
229
+ end