dr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/dr.spec ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dr/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dr"
8
+ spec.version = Dr::VERSION
9
+ spec.authors = ["Radek Pazdera"]
10
+ spec.email = ["radek@kano.me"]
11
+ spec.summary = %q{dr is a packaging tool that helps you make,
12
+ distribute and maintain you own disto packages.}
13
+ spec.description = %q{This tool works with distribution-level packaging
14
+ tools and helps you make and distribute your own
15
+ Debian packages through your own repository.}
16
+ spec.homepage = "http://github.com/KanoComputing/kano-package-system"
17
+ spec.license = "GPLv2"
18
+
19
+ spec.files = `git ls-files`.split($/)
20
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_dependency "thor", "~> 0.18.1"
25
+ spec.add_dependency "grit", "~> 2.5.0"
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.5"
28
+ spec.add_development_dependency "rake"
29
+ spec.add_development_dependency "rspec"
30
+ end
@@ -0,0 +1,6 @@
1
+ require "dr/version"
2
+ require "dr/repo"
3
+
4
+ module Dr
5
+ # Your code goes here...
6
+ end
@@ -0,0 +1,103 @@
1
+ require "tco"
2
+
3
+ require "dr/logger"
4
+ require "dr/shellcmd"
5
+
6
+ module Dr
7
+ class BuildRoot
8
+ include Logger
9
+
10
+ def initialize(arch, br_archive=nil)
11
+ @location = br_archive
12
+
13
+ @extra_pkgs = "sudo,vim,ca-certificates,fakeroot,build-essential," +
14
+ "devscripts,debhelper,git,bc,locales,equivs,pkg-config"
15
+ @repo = "http://mirrordirector.raspbian.org/raspbian/"
16
+
17
+ if br_archive == nil || !File.exists?(br_archive)
18
+ setup
19
+ end
20
+ end
21
+
22
+ def open
23
+ Dir.mktmpdir do |tmp|
24
+ log :info, "Preparing the build root"
25
+ ShellCmd.new "sudo tar xz -C #{tmp} -f #{@location}", :tag => "tar"
26
+ begin
27
+ yield tmp
28
+ ensure
29
+ log :info, "Cleaning up the buildroot"
30
+ ShellCmd.new "sudo rm -rf #{tmp}/*", :tag => "rm"
31
+ end
32
+ end
33
+ end
34
+
35
+ private
36
+ def setup(arch)
37
+ Dir.mktmpdir do |tmp|
38
+ broot = "#{tmp}/broot"
39
+ FileUtils.mkdir_p "#{tmp}/broot"
40
+
41
+ log :info, "Setting up the buildroot"
42
+
43
+ begin
44
+ log :info, "Bootstrapping Raspian (first stage)"
45
+
46
+ cmd = "sudo debootstrap --foreign --variant=buildd --no-check-gpg " +
47
+ "--include=#{@extra_pkgs} --arch=#{arch} wheezy #{broot} #{@repo}"
48
+ debootsrap = ShellCmd.new cmd, {
49
+ :tag => "debootstrap",
50
+ :show_out => true
51
+ }
52
+
53
+ static_qemu = Dir["/usr/bin/qemu-*-static"]
54
+ static_qemu.each do |path|
55
+ cp = ShellCmd.new "sudo cp #{path} #{broot}/usr/bin", {
56
+ :tag => "cp"
57
+ }
58
+ end
59
+
60
+ log :info, "Bootstrapping Raspian (#{arch} stage)"
61
+ cmd = "sudo chroot #{broot} /debootstrap/debootstrap --second-stage"
62
+ debootstrap = ShellCmd.new cmd, {
63
+ :tag => "debootstrap",
64
+ :show_out => true
65
+ }
66
+
67
+ log :info, "Configuring the build root"
68
+ cmd = "sudo chroot #{broot} <<EOF
69
+ echo 'deb #{@repo} wheezy main contrib non-free rpi' >> /etc/apt/sources.list
70
+ echo 'deb-src #{@repo} wheezy main contrib non-free rpi' >> /etc/apt/sources.list
71
+
72
+ echo 'en_US.UTF-8 UTF-8' >/etc/locale.gen
73
+ locale-gen en_US.UTF-8
74
+
75
+ cat >>/etc/bash.bashrc <<EOF2
76
+ export LANG=en_US.UTF-8
77
+ export LC_TYPE=en_US.UTF-8
78
+ export LC_ALL=en_US.UTF-8
79
+ export LANGUAGE=en_US.UTF8
80
+ EOF2
81
+ EOF"
82
+ cfg = ShellCmd.new cmd, :tag => "chroot"
83
+
84
+ log :info, "Updating package lists"
85
+ update = ShellCmd.new "sudo chroot #{broot} apt-get update", {
86
+ :tag => "chroot",
87
+ :show_out => true
88
+ }
89
+
90
+ # TODO: is this necessary?
91
+ #Kernel.system "sudo chroot #{broot} useradd -m -s /bin/bash raspbian"
92
+
93
+ log :info, "Creating the build root archive"
94
+ cmd = "sudo tar cz -C #{broot} -f #{@location} `ls -1 #{broot}`"
95
+ tar = ShellCmd.new cmd, :tag => "tar"
96
+ ensure
97
+ log :info, "Cleaning up"
98
+ ShellCmd.new "sudo rm -rf #{broot}", :tag => "rm"
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,44 @@
1
+ require "yaml"
2
+
3
+ module Dr
4
+ class Config
5
+ attr_reader :default_repo, :repositories
6
+
7
+ def initialize(locations)
8
+ @default_repo = nil
9
+ @repositories = {}
10
+
11
+ locations.each do |conf_file|
12
+ conf_file = File.expand_path conf_file
13
+ next unless File.exists? conf_file
14
+ load conf_file
15
+ end
16
+ end
17
+
18
+ private
19
+ def load(path)
20
+ conf_file = YAML::load_file path
21
+
22
+ if conf_file.has_key? "repositories"
23
+ if conf_file["repositories"].is_a? Array
24
+ conf_file["repositories"].each do |repo|
25
+ raise "Repo name missing in the config." unless repo.has_key? "name"
26
+ raise "Repo location missing in the config" unless repo.has_key? "location"
27
+ @repositories[repo["name"]] = {
28
+ :location => repo["location"]
29
+ }
30
+ end
31
+ else
32
+ raise "The 'repositories' config option must be an array."
33
+ end
34
+ end
35
+
36
+ if conf_file.has_key? "default_repo"
37
+ @default_repo = conf_file["default_repo"]
38
+ unless @repositories.has_key? @default_repo
39
+ raise "Default repo #{@default_repo} doesn't exist"
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,24 @@
1
+ require "dr/package"
2
+
3
+ module Dr
4
+ class DebPackage < Package
5
+ def self.setup(repo, deb_file)
6
+ puts "Adding the #{File.basename deb_file} package ..."
7
+ src_name = `dpkg-deb --field #{deb_file} Source`.chomp
8
+ if src_name == ""
9
+ src_name = `dpkg-deb --field #{deb_file} Package`.chomp
10
+ end
11
+ puts "Source package: #{src_name}"
12
+
13
+ version = `dpkg-deb --field #{deb_file} Version`.chomp
14
+
15
+ deb_dir = "#{repo.location}/packages/#{src_name}/builds/#{version}"
16
+ FileUtils.mkdir_p deb_dir
17
+ FileUtils.cp "#{deb_file}", "#{deb_dir}/"
18
+ end
19
+
20
+ def initialize(name, repo)
21
+ super name, repo
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,252 @@
1
+ require "dr/package"
2
+ require "dr/pkgversion"
3
+ require "dr/shellcmd"
4
+
5
+ module Dr
6
+ class GitPackage < Package
7
+ def self.setup(repo, git_addr, default_branch, force=false)
8
+ Dir.mktmpdir do |tmp|
9
+ git_cmd = "git clone --branch #{default_branch} #{git_addr} #{tmp}/git"
10
+ ShellCmd.new git_cmd, :tag => "git", :show_out => true
11
+
12
+ unless File.exists? "#{tmp}/git/debian/control"
13
+ log :err, "The debian packaging files not found in the repository"
14
+ raise "Adding a package from #{git_addr} failed"
15
+ end
16
+
17
+ src_name = nil
18
+ File.open "#{tmp}/git/debian/control", "r" do |f|
19
+ f.each_line do |line|
20
+ match = line.match /^Source: (.+)$/
21
+ if match
22
+ src_name = match.captures[0]
23
+ break
24
+ end
25
+ end
26
+ end
27
+
28
+ unless src_name
29
+ log :err, "Couldn't identify the source package"
30
+ raise "Adding a package from #{git_addr} failed"
31
+ end
32
+
33
+ pkg_dir = "#{repo.location}/packages/#{src_name}"
34
+ if File.exists? pkg_dir
35
+ log :warn, "The package already exists. Add -f to insert it anyway."
36
+ raise "Adding failed"
37
+ end
38
+
39
+ log :info, "Adding #{src_name.fg "blue"} to the repository"
40
+ FileUtils.mkdir_p "#{pkg_dir}"
41
+
42
+ log :info, "Setting up builds directory"
43
+ FileUtils.mkdir_p "#{pkg_dir}/builds"
44
+
45
+ log :info, "Setting up the source directory"
46
+ FileUtils.mv "#{tmp}/git/.git", "#{pkg_dir}/source"
47
+
48
+ log :info, "Package #{src_name} added successfully"
49
+ end
50
+ end
51
+
52
+ def initialize(name, repo)
53
+ super name, repo
54
+
55
+ @git_dir = "#{repo.location}/packages/#{name}/source"
56
+
57
+ git_cmd = ShellCmd.new "git --git-dir #{@git_dir} branch", {
58
+ :tag => "git-clone"
59
+ }
60
+ @default_branch = git_cmd.out.chomp.lines.grep(/^*/)[0][2..-1]
61
+ end
62
+
63
+ def build(branch=nil, force=false)
64
+ branch = @default_branch unless branch
65
+
66
+ version = nil
67
+ orig_rev, curr_rev = update_from_origin branch
68
+ if curr_rev != orig_rev || force
69
+ Dir.mktmpdir do |src_dir|
70
+ log :info, "Extracting the sources"
71
+ git_cmd ="git --git-dir #{@git_dir} archive " +
72
+ "--format tar #{branch} | tar x -C #{src_dir}"
73
+ ShellCmd.new git_cmd, :tag => "git", :show_out => true
74
+
75
+ version = PkgVersion.new get_version "#{src_dir}/debian/changelog"
76
+ log :info, "Source version: #{version}"
77
+
78
+ while build_exists? version
79
+ version.increment!
80
+ end
81
+ log :info, "Building version: #{version}"
82
+
83
+ log :info, "Updating changelog"
84
+ now = Time.new.strftime("%a, %-d %b %Y %T %z")
85
+ ch_entry = "#{@name} (#{version}) kano; urgency=low\n"
86
+ ch_entry << "\n"
87
+ ch_entry << " * Package rebuilt, updated to revision #{curr_rev[0..7]}.\n"
88
+ ch_entry << "\n"
89
+ ch_entry << " -- Team Kano <dev@kano.me> #{now}\n\n"
90
+
91
+ changelog = ""
92
+ File.open "#{src_dir}/debian/changelog", "r" do |f|
93
+ changelog = f.read
94
+ end
95
+
96
+ File.open "#{src_dir}/debian/changelog", "w" do |f|
97
+ f.write ch_entry
98
+ f.write changelog
99
+ end
100
+
101
+ repo_arches = @repo.get_architectures
102
+ pkg_arches = get_architectures("#{src_dir}/debian/control")
103
+ arches = case
104
+ when pkg_arches.include?("any") || pkg_arches.include?("all")
105
+ repo_arches
106
+ else
107
+ repo_arches & pkg_arches
108
+ end
109
+ arches.each do |arch|
110
+ @repo.buildroot(arch).open do |br|
111
+ log :info, "Building the #{@name.fg("blue")} package " +
112
+ "v#{version} for #{arch}"
113
+ # Moving to the proper directory
114
+ build_dir_name = "#{@name}-#{version.upstream}"
115
+ build_dir = "#{br}/#{build_dir_name}"
116
+ FileUtils.cp_r src_dir, build_dir
117
+
118
+ # Make orig tarball
119
+ log :info, "Creating orig source tarball"
120
+ tar = "tar cz -C #{build_dir} --exclude=debian " +
121
+ "-f #{br}/#{@name}_#{version.upstream}.orig.tar.gz " +
122
+ "`ls -1 #{build_dir}`"
123
+ ShellCmd.new tar, :tag => "tar"
124
+
125
+ apt = "sudo chroot #{br} apt-get update"
126
+ deps = <<-EOS
127
+ sudo chroot #{br} <<EOF
128
+ dpkg-source -b "/#{build_dir_name}"
129
+ mk-build-deps *.dsc -i -t "apt-get --no-install-recommends -y"
130
+ rm -rf #{@name}-build-deps_*
131
+ EOF
132
+ EOS
133
+ build = <<-EOS
134
+ sudo chroot #{br} <<EOF
135
+ cd /#{build_dir_name}
136
+ debuild -i -uc -us -b
137
+ EOF
138
+ EOS
139
+
140
+ log :info, "Updating the sources lists"
141
+ ShellCmd.new apt, :tag => "apt-get", :show_out => true
142
+
143
+ log :info, "Installing build dependencies"
144
+ ShellCmd.new deps, :tag => "mk-build-deps", :show_out => true
145
+
146
+ log :info, "Building the package"
147
+ ShellCmd.new build, :tag => "debuild", :show_out => true
148
+
149
+ debs = Dir["#{br}/*.deb"]
150
+ expected_pkgs = get_subpackage_names "#{src_dir}/debian/control"
151
+ expected_pkgs.each do |subpkg_name|
152
+ includes = debs.inject(false) do |r, n|
153
+ r || ((/^#{br}\/#{subpkg_name}_#{version}/ =~ n) != nil)
154
+ end
155
+
156
+ unless includes
157
+ log :err, "Subpackage #{subpkg_name} did not build properly"
158
+ raise "Building #{name} failed"
159
+ end
160
+ end
161
+
162
+ build_dir = "#{@repo.location}/packages/#{@name}/builds/#{version}"
163
+ FileUtils.mkdir_p build_dir
164
+ debs.each do |pkg|
165
+ FileUtils.cp pkg, build_dir
166
+ end
167
+ end
168
+ end
169
+ end
170
+ else
171
+ log :info, "There were no changes in the #{pkg.name.fg("blue")} package"
172
+ log :info, "Build stopped (add -f to build anyway)"
173
+ end
174
+ version
175
+ end
176
+
177
+ def build_exists?(version)
178
+ File.directory? "#{@repo.location}/packages/#{@name}/builds/#{version}"
179
+ end
180
+
181
+ def remove_build(version)
182
+ raise "Build #{version.fg("blue")} not found" unless build_exists? version
183
+ FileUtils.rm_rf "#{@repo.location}/packages/#{@name}/builds/#{version}"
184
+ end
185
+
186
+ private
187
+ def update_from_origin(branch)
188
+ log :info, "Pulling changes from origin"
189
+
190
+ git_cmd = "git --git-dir #{@git_dir} rev-parse #{branch} 2>/dev/null"
191
+ git = ShellCmd.new git_cmd, :tag => "git"
192
+
193
+ original_rev = git.out.chomp
194
+ original_rev = nil if original_rev == branch
195
+
196
+ begin
197
+ if @default_branch == branch
198
+ git_cmd = "git --git-dir #{@git_dir} pull origin #{branch}"
199
+ ShellCmd.new git_cmd, :tag => "git", :show_out => true
200
+ else
201
+ git_cmd = "git --git-dir #{@git_dir} fetch origin #{branch}:#{branch}"
202
+ ShellCmd.new git_cmd, :tag => "git", :show_out => true
203
+ end
204
+ rescue Exception => e
205
+ log :err, "Unable to pull from origin"
206
+ raise e
207
+ end
208
+
209
+ git_cmd = "git --git-dir #{@git_dir} rev-parse #{branch} 2>/dev/null"
210
+ git = ShellCmd.new git_cmd, :tag => "git"
211
+ current_rev = git.out.chomp
212
+
213
+ [original_rev, current_rev]
214
+ end
215
+
216
+ def get_version(changelog_file)
217
+ File.open changelog_file, "r" do |f|
218
+ f.each_line do |l|
219
+ version = l.match /^#{@name} \(([^\)]+)\) .+;/
220
+ return version.captures[0] if version
221
+ end
222
+ end
223
+
224
+ nil
225
+ end
226
+
227
+ def get_subpackage_names(control_file)
228
+ packages = []
229
+ File.open control_file, "r" do |f|
230
+ f.each_line do |l|
231
+ if /^Package: / =~ l
232
+ packages.push l.split(" ")[1]
233
+ end
234
+ end
235
+ end
236
+
237
+ packages
238
+ end
239
+
240
+ def get_architectures(control_file)
241
+ arches = []
242
+ File.open control_file, "r" do |f|
243
+ f.each_line do |l|
244
+ m = l.match /^Architecture: (.+)/
245
+ arches += m.captures[0].chomp.split(" ") if m
246
+ end
247
+ end
248
+
249
+ arches.uniq
250
+ end
251
+ end
252
+ end