dr 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.
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