Skip to content

Commit

Permalink
Add a plans/build_order.rb which generates a build order for Plans.
Browse files Browse the repository at this point in the history
The `plans/build_order.rb` is a Ruby program with no external library
dependencies, but it may call out to the `plans/build-base-plans.sh`
program which is assumed to be in the same directory.

The program is fed paths to `plan.sh` files on stdin which are used as
the input set of packages and dependencies. For example:

    find . -name plan.sh | ./plans/build_order.rb

Would find all plans in our project and determine the build order for
all of them. At the moment, only `core` origin Plans are considered (the
rest are ignored).

If the base set of packages have been built, as is usually the case, you
can add a `--without-base` flag to the program which, after sorting,
will remove all package identifers contained in the
`plans/build-base-plans.sh` program--which gets called with a
`$PRINT_IDENTS_ONLY` environment variable set. For example:

    find . -name plan.sh | ./plans/build_order.rb --without-base

Note that this program can be run on a Mac (which has a version of Ruby
already), in the devshell (assuming you install a Ruby package), or in a
Studio (assuming you build/install a `core/ruby`).

Signed-off-by: Fletcher Nichol <fnichol@nichol.ca>

Pull request: #464
Approved by: smith
  • Loading branch information
fnichol committed Jul 4, 2016
1 parent 439c52e commit 5951283
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
.DEFAULT_GOAL := base

base: ## builds all base packages in serial order
sh ./build-base-plans.sh
bash ./build-base-plans.sh

help:
@perl -nle'print $& if m{^[a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
Expand Down
4 changes: 3 additions & 1 deletion bash-static/plan.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ pkg_build_deps=("${pkg_deps[@]}" "${pkg_build_deps[@]}")
# Empty out the run deps array
pkg_deps=()

PLAN_CONTEXT=$(abspath ../bash)
do_begin() {
PLAN_CONTEXT=$(abspath ../bash)
}

do_build() {
./configure \
Expand Down
11 changes: 9 additions & 2 deletions build-base-plans.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
#
# # Usage
#
Expand Down Expand Up @@ -77,6 +77,9 @@ origin=core
# ```
_on_exit() {
local exit_status=${1:-$?}
if [ -n "${PRINT_IDENTS_ONLY:-}" ]; then
exit $?
fi
local elapsed=$SECONDS
elapsed=$(echo $elapsed | awk '{printf "%dm%ds", $1/60, $1%60}')
printf -- "\n$(basename $0) run time: $elapsed\n\n"
Expand Down Expand Up @@ -111,12 +114,16 @@ _build() {
# If the `$plan` value is a path/name combination like
# `../components/foobar:hab-foobar` then split the token into its requisite
# parts.
case $(echo "$plan" | grep -o ':' | wc -l) in
case $(echo "$plan" | grep -o ':' | wc -l | sed 's,^[^0-9]*,,') in
1)
plan_dir=$(echo $plan | cut -d ':' -f 1)
plan=$(echo $plan | cut -d ':' -f 2)
;;
esac
if [ -n "${PRINT_IDENTS_ONLY:-}" ]; then
echo "${origin}/$plan"
return 0
fi
# If the `$STOP_BEFORE` environment variable is set, and its value is the
# desired Plan, then we'll stop. This is a convenient way to build up to an
# interesting Plan without steamrolling right over it.
Expand Down
90 changes: 90 additions & 0 deletions build_order.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/env ruby

require 'delegate'
require 'optparse'
require 'tsort'
require 'tempfile'

# Command line parser
class Cli
def self.parse(argv) # rubocop:disable Metrics/MethodLength
options = { with_base: true }
parser = OptionParser.new do |opts|
opts.banner = "Usage: #{File.basename(__FILE__)} [--without-base]"
opts.on('--without-base', "Don't include base packages in result") do |_|
options[:with_base] = false
end
opts.on('-h', '--help', 'Prints this help') do
puts opts
exit
end
opts.separator ''
opts.separator 'Examples:'
opts.separator " find . -name plan.sh | #{__FILE__}"
opts.separator " find . -name plan.sh | #{__FILE__} --without-base"
end
parser.parse!(argv)
options
end
end

# Dependency tracker.
class Sortable < SimpleDelegator
include TSort

def add(ident, deps = [])
__getobj__[ident] = deps
end

def tsort_each_node(&block)
__getobj__.each_key(&block)
end

def tsort_each_child(node, &block)
__getobj__.fetch(node).each(&block)
end
end

options = Cli.parse(ARGV)

bash_prog = Tempfile.new('print_deps.sh')
bash_prog.write(<<'EOF')
#!/bin/bash
set -e
STUDIO_TYPE=stage1
FIRST_PASS=true
cd $(dirname $1)
source $(basename $1)
echo "${pkg_origin}/${pkg_name}"
echo "${pkg_build_deps[*]} ${pkg_deps[*]}"
exit 0
EOF
bash_prog.close

all_deps = Sortable.new({})
ARGF.each_line do |file|
raw = `bash #{bash_prog.path} #{file}`.chomp
ident, _, deps_str = raw.partition(/\n/)
if ident.start_with?('core/')
all_deps.add(ident, deps_str.split(' ')
.map { |d| d.split('/').first(2).join('/') })
end
end

all_deps.keys.each do |ident|
all_deps[ident].each do |dep|
all_deps.add(dep) unless all_deps.key?(dep)
end
end

sorted_deps = all_deps.tsort

unless options[:with_base]
prog = "#{File.dirname(__FILE__)}/build-base-plans.sh"
raw = `env PRINT_IDENTS_ONLY=true #{prog}`.chomp
base_deps = raw.split(/\n/)
sorted_deps.delete_if { |dep| base_deps.include?(dep) }
end

puts sorted_deps
7 changes: 6 additions & 1 deletion patchelf/plan.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,16 @@ if [[ -n "$FIRST_PASS" ]]; then
# this package to prepare gcc-libs, we'll do the cheap version first
# that relies on the full gcc version of these shared libraries
pkg_deps=(core/glibc core/gcc)
build_line "Using libgcc and libstdc++ from core/gcc"
else
pkg_deps=(core/glibc core/gcc-libs)
fi

do_begin() {
if [[ -n "$FIRST_PASS" ]]; then
build_line "Using libgcc and libstdc++ from core/gcc"
fi
}


# ----------------------------------------------------------------------------
# **NOTICE:** What follows are implementation details required for building a
Expand Down
18 changes: 10 additions & 8 deletions readline/plan.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ pkg_build_deps=(core/coreutils core/diffutils core/patch core/make core/gcc core
pkg_include_dirs=(include)
pkg_lib_dirs=(lib)

# The maintainer of Readline only releases these patches to fix serious issues,
# so any new official patches will be part of this build, which will be
# reflected in the "tiny" or "patch" number of the version coordinate. In other
# words, given 6 patches, the version of this Readline package would be
# `MAJOR.MINOR.6`.
do_begin() {
# The maintainer of Readline only releases these patches to fix serious issues,
# so any new official patches will be part of this build, which will be
# reflected in the "tiny" or "patch" number of the version coordinate. In other
# words, given 6 patches, the version of this Readline package would be
# `MAJOR.MINOR.6`.

# Source a file containing an array of patch URLs and an array of patch file
# shasums
source $PLAN_CONTEXT/readline-patches.sh
# Source a file containing an array of patch URLs and an array of patch file
# shasums
source $PLAN_CONTEXT/readline-patches.sh
}

do_download() {
do_default_download
Expand Down

0 comments on commit 5951283

Please sign in to comment.