autoproj 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +2 -0
- data/Manifest.txt +37 -0
- data/README.txt +79 -0
- data/Rakefile +84 -0
- data/bin/autoproj +465 -0
- data/doc/guide/config.yaml +30 -0
- data/doc/guide/ext/init.rb +17 -0
- data/doc/guide/ext/previous_next.rb +40 -0
- data/doc/guide/ext/rdoc_links.rb +33 -0
- data/doc/guide/src/autobuild.page +111 -0
- data/doc/guide/src/autoproj_bootstrap +218 -0
- data/doc/guide/src/default.css +325 -0
- data/doc/guide/src/default.template +74 -0
- data/doc/guide/src/htmldoc.metainfo +4 -0
- data/doc/guide/src/images/bodybg.png +0 -0
- data/doc/guide/src/images/contbg.png +0 -0
- data/doc/guide/src/images/footerbg.png +0 -0
- data/doc/guide/src/images/gradient1.png +0 -0
- data/doc/guide/src/images/gradient2.png +0 -0
- data/doc/guide/src/index.page +79 -0
- data/doc/guide/src/source_yml.page +139 -0
- data/doc/guide/src/structure.page +153 -0
- data/lib/autoproj.rb +23 -0
- data/lib/autoproj/autobuild.rb +173 -0
- data/lib/autoproj/default.osdeps +12 -0
- data/lib/autoproj/manifest.rb +697 -0
- data/lib/autoproj/options.rb +137 -0
- data/lib/autoproj/osdeps.rb +134 -0
- data/lib/autoproj/system.rb +66 -0
- data/lib/autoproj/version.rb +3 -0
- data/samples/manifest +9 -0
- data/samples/manifest.xml +20 -0
- data/samples/osdeps.yml +65 -0
- data/test/data/test_manifest/autoproj/local/local.autobuild +0 -0
- data/test/data/test_manifest/autoproj/manifest +8 -0
- data/test/test_debian.rb +16 -0
- data/test/test_manifest.rb +40 -0
- metadata +199 -0
@@ -0,0 +1,137 @@
|
|
1
|
+
module Autoproj
|
2
|
+
class InputError < RuntimeError; end
|
3
|
+
|
4
|
+
class BuildOption
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :type
|
7
|
+
attr_reader :options
|
8
|
+
|
9
|
+
attr_reader :validator
|
10
|
+
|
11
|
+
TRUE_STRINGS = %w{on yes y true}
|
12
|
+
FALSE_STRINGS = %w{off no n false}
|
13
|
+
def initialize(name, type, options, validator)
|
14
|
+
@name, @type, @options = name.to_str, type.to_str, options.to_hash
|
15
|
+
@validator = validator.to_proc if validator
|
16
|
+
if !BuildOption.respond_to?("validate_#{type}")
|
17
|
+
raise ConfigError, "invalid option type #{type}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def doc
|
22
|
+
options[:doc] || "#{name} (no documentation for this option)"
|
23
|
+
end
|
24
|
+
|
25
|
+
def ask(current_value)
|
26
|
+
default_value = if current_value then current_value
|
27
|
+
else options[:default]
|
28
|
+
end
|
29
|
+
|
30
|
+
STDERR.print " #{doc} [#{default_value}] "
|
31
|
+
answer = STDIN.readline.chomp
|
32
|
+
if answer == ''
|
33
|
+
answer = default_value
|
34
|
+
end
|
35
|
+
validate(answer)
|
36
|
+
|
37
|
+
rescue InputError => e
|
38
|
+
STDERR.puts Autoproj.console.color("invalid value: #{e.message}", :red)
|
39
|
+
retry
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate(value)
|
43
|
+
value = BuildOption.send("validate_#{type}", value, options)
|
44
|
+
if validator
|
45
|
+
value = validator[value]
|
46
|
+
end
|
47
|
+
value
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.validate_boolean(value, options)
|
51
|
+
if TRUE_STRINGS.include?(value.downcase)
|
52
|
+
true
|
53
|
+
elsif FALSE_STRINGS.include?(value.downcase)
|
54
|
+
false
|
55
|
+
else
|
56
|
+
raise InputError, "invalid boolean value '#{value}', accepted values are '#{TRUE_STRINGS.join(", ")}' for true, and '#{FALSE_STRINGS.join(", ")} for false"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.validate_string(value, options)
|
61
|
+
if possible_values = options[:possible_values]
|
62
|
+
if !possible_values.include?(value)
|
63
|
+
raise InputError, "invalid value '#{value}', accepted values are '#{possible_values.join(", ")}'"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
@user_config = Hash.new
|
71
|
+
|
72
|
+
def self.option_set
|
73
|
+
@user_config.inject(Hash.new) do |h, (k, v)|
|
74
|
+
h[k] = v.first
|
75
|
+
h
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.user_config(key)
|
80
|
+
value, seen = @user_config[key]
|
81
|
+
|
82
|
+
if value.nil? || (!seen && Autoproj.reconfigure?)
|
83
|
+
value = configure(key)
|
84
|
+
else
|
85
|
+
if !seen
|
86
|
+
STDERR.puts " #{@declared_options[key].doc}: #{value}"
|
87
|
+
@user_config[key] = [value, true]
|
88
|
+
end
|
89
|
+
value
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
@declared_options = Hash.new
|
94
|
+
def self.configuration_option(name, type, options, &validator)
|
95
|
+
@declared_options[name] = BuildOption.new(name, type, options, validator)
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.configure(option_name)
|
99
|
+
if opt = @declared_options[option_name]
|
100
|
+
if current_value = @user_config[option_name]
|
101
|
+
current_value = current_value.first
|
102
|
+
end
|
103
|
+
value = opt.ask(current_value)
|
104
|
+
@user_config[option_name] = [value, true]
|
105
|
+
value
|
106
|
+
else
|
107
|
+
raise ConfigError, "undeclared option '#{option_name}'"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.save_config
|
112
|
+
File.open(File.join(Autoproj.config_dir, "config.yml"), "w") do |io|
|
113
|
+
config = Hash.new
|
114
|
+
@user_config.each_key do |key|
|
115
|
+
config[key] = @user_config[key].first
|
116
|
+
end
|
117
|
+
|
118
|
+
io.write YAML.dump(config)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.load_config
|
123
|
+
config_file = File.join(Autoproj.config_dir, "config.yml")
|
124
|
+
if File.exists?(config_file)
|
125
|
+
config = YAML.load(File.read(config_file))
|
126
|
+
config.each do |key, value|
|
127
|
+
@user_config[key] = [value, false]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
class << self
|
133
|
+
attr_accessor :reconfigure
|
134
|
+
end
|
135
|
+
def self.reconfigure?; @reconfigure end
|
136
|
+
end
|
137
|
+
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
module Autoproj
|
3
|
+
class OSDependencies
|
4
|
+
def self.load(file)
|
5
|
+
OSDependencies.new(YAML.load(File.read(file)))
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :definitions
|
9
|
+
def initialize(defs = Hash.new)
|
10
|
+
@definitions = defs.to_hash
|
11
|
+
end
|
12
|
+
|
13
|
+
def merge(info)
|
14
|
+
@definitions = definitions.merge(info.definitions)
|
15
|
+
end
|
16
|
+
|
17
|
+
def operating_system
|
18
|
+
if File.exists?('/etc/debian_version')
|
19
|
+
codename = File.read('/etc/debian_version').chomp
|
20
|
+
['debian', codename]
|
21
|
+
else
|
22
|
+
raise ConfigError, "Unknown operating system"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
GAIN_ROOT_ACCESS = <<-EOSCRIPT
|
27
|
+
if test `id -u` != "0"; then
|
28
|
+
exec sudo /bin/bash $0 "$@"
|
29
|
+
|
30
|
+
fi
|
31
|
+
EOSCRIPT
|
32
|
+
|
33
|
+
OS_PACKAGE_INSTALL = {
|
34
|
+
'debian' => 'apt-get install -y %s'
|
35
|
+
}
|
36
|
+
|
37
|
+
def generate_os_script(dependencies)
|
38
|
+
os_name, os_version = operating_system
|
39
|
+
shell_snippets = ""
|
40
|
+
os_packages = []
|
41
|
+
dependencies.each do |name|
|
42
|
+
dep_def = definitions[name]
|
43
|
+
if !dep_def
|
44
|
+
raise ConfigError, "I don't know how to install '#{name}'"
|
45
|
+
elsif !dep_def[os_name]
|
46
|
+
raise ConfigError, "I don't know how to install '#{name}' on #{os_name}"
|
47
|
+
end
|
48
|
+
|
49
|
+
data = dep_def[os_name]
|
50
|
+
if data.kind_of?(Hash)
|
51
|
+
data = data[os_version]
|
52
|
+
if !data
|
53
|
+
raise ConfigError, "I don't know how to install '#{name}' on this specific version of #{os_name} (#{os_version})"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if data.respond_to?(:to_ary)
|
58
|
+
os_packages.concat data.to_ary
|
59
|
+
elsif data.to_str =~ /\w+/
|
60
|
+
os_packages << data.to_str
|
61
|
+
else
|
62
|
+
shell_snippets << "\n" << data << "\n"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
"#! /bin/bash\n" +
|
67
|
+
GAIN_ROOT_ACCESS + "\n" +
|
68
|
+
(OS_PACKAGE_INSTALL[os_name] % [os_packages.join(" ")]) +
|
69
|
+
"\n" + shell_snippets
|
70
|
+
end
|
71
|
+
|
72
|
+
def partition_packages(package_set)
|
73
|
+
package_set = package_set.to_set
|
74
|
+
osdeps, gems = [], []
|
75
|
+
package_set.to_set.each do |name|
|
76
|
+
pkg_def = definitions[name]
|
77
|
+
if !pkg_def
|
78
|
+
raise ConfigError, "I know nothing about a prepackaged '#{name}' software"
|
79
|
+
end
|
80
|
+
|
81
|
+
if pkg_def.respond_to?(:to_str)
|
82
|
+
case(pkg_def.to_str)
|
83
|
+
when "gem" then
|
84
|
+
gems << name
|
85
|
+
else
|
86
|
+
raise ConfigError, "unknown OS-independent package management type #{pkg_def}"
|
87
|
+
end
|
88
|
+
else
|
89
|
+
osdeps << name
|
90
|
+
end
|
91
|
+
end
|
92
|
+
return osdeps, gems
|
93
|
+
end
|
94
|
+
|
95
|
+
def install(packages)
|
96
|
+
osdeps, gems = partition_packages(packages)
|
97
|
+
|
98
|
+
# Ideally, we would feed the OS dependencies to rosdep.
|
99
|
+
# Unfortunately, this is C++ code and I don't want to install the
|
100
|
+
# whole ROS stack just for rosdep ...
|
101
|
+
#
|
102
|
+
# So, for now, reimplement rosdep by ourselves. Given how things
|
103
|
+
# are done, this is actually not so hard.
|
104
|
+
shell_script = generate_os_script(osdeps)
|
105
|
+
if Autoproj.verbose
|
106
|
+
STDERR.puts "Installing non-ruby OS dependencies with"
|
107
|
+
STDERR.puts shell_script
|
108
|
+
end
|
109
|
+
|
110
|
+
File.open('osdeps.sh', 'w') do |file|
|
111
|
+
file.write shell_script
|
112
|
+
end
|
113
|
+
Autobuild::Subprocess.run 'autoproj', 'osdeps', 'bash', './osdeps.sh'
|
114
|
+
FileUtils.rm_f 'osdeps.sh'
|
115
|
+
|
116
|
+
# Don't install gems that are already there ...
|
117
|
+
gems.delete_if do |name|
|
118
|
+
version_requirements = Gem::Requirement.default
|
119
|
+
available = Gem.source_index.find_name(name, version_requirements)
|
120
|
+
!available.empty?
|
121
|
+
end
|
122
|
+
|
123
|
+
# Now install what is left
|
124
|
+
if !gems.empty?
|
125
|
+
if Autoproj.verbose
|
126
|
+
STDERR.puts "Installing rubygems dependencies with"
|
127
|
+
STDERR.puts "gem install #{gems.join(" ")}"
|
128
|
+
end
|
129
|
+
Autobuild::Subprocess.run 'autoproj', 'osdeps', 'gem', 'install', *gems
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Autoproj
|
2
|
+
BASE_DIR = File.expand_path(File.join('..', '..'), File.dirname(__FILE__))
|
3
|
+
|
4
|
+
class UserError < RuntimeError; end
|
5
|
+
|
6
|
+
def self.root_dir
|
7
|
+
dir = Dir.pwd
|
8
|
+
while dir != "/" && !File.directory?(File.join(dir, "autoproj"))
|
9
|
+
dir = File.dirname(dir)
|
10
|
+
end
|
11
|
+
if dir == "/"
|
12
|
+
raise UserError, "not in a Autoproj installation"
|
13
|
+
end
|
14
|
+
dir
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.config_dir
|
18
|
+
File.join(root_dir, "autoproj")
|
19
|
+
end
|
20
|
+
def self.build_dir
|
21
|
+
File.join(root_dir, "build")
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.config_file(file)
|
25
|
+
File.join(config_dir, file)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.run_as_user(*args)
|
29
|
+
if !system(*args)
|
30
|
+
raise "failed to run #{args.join(" ")}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.run_as_root(*args)
|
35
|
+
if !system('sudo', *args)
|
36
|
+
raise "failed to run #{args.join(" ")} as root"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.set_initial_env
|
41
|
+
gem_home = File.join(Autoproj.config_dir, "gems")
|
42
|
+
Autoproj.env_set 'RUBYOPT', "-rubygems"
|
43
|
+
Autoproj.env_set 'GEM_HOME', gem_home
|
44
|
+
Autoproj.env_set_path 'PATH', "#{gem_home}/bin", "/usr/local/bin", "/usr/bin", "/bin"
|
45
|
+
Autoproj.env_set 'PKG_CONFIG_PATH'
|
46
|
+
Autoproj.env_set 'RUBYLIB'
|
47
|
+
Autoproj.env_inherit 'PATH', 'PKG_CONFIG_PATH', 'RUBYLIB'
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.export_env_sh(subdir)
|
51
|
+
File.open(File.join(Autoproj.root_dir, subdir, "env.sh"), "w") do |io|
|
52
|
+
Autobuild.environment.each do |name, value|
|
53
|
+
shell_line = "export #{name}=#{value.join(":")}"
|
54
|
+
if Autoproj.env_inherit?(name)
|
55
|
+
if value.empty?
|
56
|
+
next
|
57
|
+
else
|
58
|
+
shell_line << ":$#{name}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
io.puts shell_line
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
data/samples/manifest
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
sources:
|
2
|
+
# Example source from a git repository
|
3
|
+
# - type: git
|
4
|
+
# url: git://github.com/doudou/autoproj.orocos.git
|
5
|
+
#
|
6
|
+
# If you want to enable only a subset of the listed sources,
|
7
|
+
# list their names in the following section. Note that the
|
8
|
+
# name is given in the source's source.yml file
|
9
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<package>
|
2
|
+
<description brief="one line of text">
|
3
|
+
long description goes here,
|
4
|
+
<em>XHTML is allowed</em>
|
5
|
+
</description>
|
6
|
+
<author>Alice/alice@somewhere.bar, Bob/bob@nowhere.foo</author>
|
7
|
+
<license>BSD</license>
|
8
|
+
<url>http://pr.willowgarage.com/</url>
|
9
|
+
<logo>http://pr.willowgarage.com/blog/photos/sensor_head1_500.jpg</logo>
|
10
|
+
|
11
|
+
<depend package="pkgname"/>
|
12
|
+
<depend package="common"/>
|
13
|
+
<rosdep name="python" />
|
14
|
+
<versioncontrol type="svn" url="https://playerstage.svn.sourceforge.net/svnroot/playerstage/code/player/trunk"/>
|
15
|
+
<export>
|
16
|
+
<cpp cflags="-I${prefix}/include" lflags="-L${prefix}/lib -lros"/>
|
17
|
+
<cpp os="osx" cflags="-I${prefix}/include" lflags="-L${prefix}/lib -Wl,-rpath,-L${prefix}lib -lrosthread -framework CoreServices"/>
|
18
|
+
</export>
|
19
|
+
|
20
|
+
</package>
|
data/samples/osdeps.yml
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
wxpython:
|
2
|
+
ubuntu: python-wxgtk2.8
|
3
|
+
arch: wxpython
|
4
|
+
centos: wxPython-devel
|
5
|
+
debian: python-wxgtk2.8
|
6
|
+
log4cxx:
|
7
|
+
ubuntu:
|
8
|
+
9.04: liblog4cxx10-dev
|
9
|
+
8.10: |
|
10
|
+
if [ ! -f /opt/ros/lib/liblog4cxx.so.10 ] ; then
|
11
|
+
mkdir -p ~/ros/ros-deps
|
12
|
+
cd ~/ros/ros-deps
|
13
|
+
wget --tries=10 http://pr.willowgarage.com/downloads/apache-log4cxx-0.10.0-wg_patched.tar.gz
|
14
|
+
tar xzf apache-log4cxx-0.10.0-wg_patched.tar.gz
|
15
|
+
cd apache-log4cxx-0.10.0
|
16
|
+
./configure --prefix=/opt/ros
|
17
|
+
make
|
18
|
+
sudo make install
|
19
|
+
fi
|
20
|
+
8.04: |
|
21
|
+
if [ ! -f /opt/ros/lib/liblog4cxx.so.10 ] ; then
|
22
|
+
mkdir -p ~/ros/ros-deps
|
23
|
+
cd ~/ros/ros-deps
|
24
|
+
wget --tries=10 http://pr.willowgarage.com/downloads/apache-log4cxx-0.10.0-wg_patched.tar.gz
|
25
|
+
tar xzf apache-log4cxx-0.10.0-wg_patched.tar.gz
|
26
|
+
cd apache-log4cxx-0.10.0
|
27
|
+
./configure --prefix=/opt/ros
|
28
|
+
make
|
29
|
+
sudo make install
|
30
|
+
fi
|
31
|
+
debian:
|
32
|
+
squeeze/sid: liblog4cxx10-dev
|
33
|
+
lenny: |
|
34
|
+
if [ ! -f /opt/ros/lib/liblog4cxx.so.10 ] ; then
|
35
|
+
mkdir -p ~/ros/ros-deps
|
36
|
+
cd ~/ros/ros-deps
|
37
|
+
wget --tries=10 http://pr.willowgarage.com/downloads/apache-log4cxx-0.10.0-wg_patched.tar.gz
|
38
|
+
tar xzf apache-log4cxx-0.10.0-wg_patched.tar.gz
|
39
|
+
cd apache-log4cxx-0.10.0
|
40
|
+
./configure --prefix=/opt/ros
|
41
|
+
make
|
42
|
+
sudo make install
|
43
|
+
fi
|
44
|
+
fedora: log4cxx-devel
|
45
|
+
arch: |
|
46
|
+
if [ ! -f /usr/lib/liblog4cxx.so.10 ] ; then
|
47
|
+
mkdir -p ~/ros/ros-deps
|
48
|
+
cd ~/ros/ros-deps
|
49
|
+
wget --tries=10 http://aur.archlinux.org/packages/log4cxx/log4cxx.tar.gz
|
50
|
+
tar xzf log4cxx.tar.gz
|
51
|
+
cd log4cxx
|
52
|
+
makepkg
|
53
|
+
sudo pacman -U log4cxx-*.pkg.tar.gz
|
54
|
+
fi
|
55
|
+
macports: |
|
56
|
+
if [ ! -f /opt/ros/lib/liblog4cxx.so.10 ] ; then
|
57
|
+
mkdir -p ~/ros/ros-deps
|
58
|
+
cd ~/ros/ros-deps
|
59
|
+
wget --tries=10 http://pr.willowgarage.com/downloads/apache-log4cxx-0.10.0-wg_patched.tar.gz
|
60
|
+
tar xzf apache-log4cxx-0.10.0-wg_patched.tar.gz
|
61
|
+
cd apache-log4cxx-0.10.0
|
62
|
+
./configure --prefix=/opt/ros
|
63
|
+
make
|
64
|
+
sudo make install
|
65
|
+
fi
|
File without changes
|