Radix cross Linux Build System

Cross-platform build system is designed to build distributions of different operating systems for a set of target devices

39 Commits   2 Branches   2 Tags
#!/bin/env perl

use FindBin;
use lib $FindBin::Bin;

use strict;
use warnings FATAL => 'all';

use IO::Handle;
use File::Basename;
use File::Temp;
use Getopt::Long;

use _kxLab;

#
# Generate $(TARGET_BUILD_DIR)/.DEVLIST file
#
# usage:
#   $0 [options] topdir toolchain hardware flavour
#
# where:
#      'topdir' - is a absolute path to the top directory of checked out branch
#   'toolchain' - is a TOOLCHAIN name
#    'hardware' - is a HARDWARE  name
#     'flavour' - is a HARDWARE  variant
#

my (%devices, $devices_file);
my ($products_dest_dir, $pkglist_file);
my ($top_dir, $toolchain, $hardware, $flavour, $target_build_dir);
my ($system_version, $distro_version, $distro_name);
my ($arch, $products_base_dir);


sub usage
{
  print <<EOF;

Usage: build_devices_list [options] topdir toolchain hardware [flavour]
Options:
  -a, --arch=<z|j|J>
                 - where 'z' is gzip, 'j' is bzip2, and 'J' is xz arcive format;

  -p, --products-dir=<DIR>
                 - base name of products dir default value is 'products';

Args:
          topdir - is a absolute path to the top of checked out branch;
       toolchain - is a TOOLCHAIN name;
        hardware - is a HARDWARE name.
         flavour - is a HARDWARE variant.

EOF
  exit;
}


#
# http://permissions-calculator.org
#
sub text2spec_mode
{
  my $tmode = shift;
  my $smode = '0';

  foreach my $ugo ( $tmode =~ /^.(.{3})(.{3})(.{3})/ )
  {
    $ugo =~ /[SsTt]/ && ($smode += 1);
  }
  return $smode;
}

sub text2oct_mode
{
  my $tmode = shift;
  my $omode = '0';

  if( $tmode =~ /^.(.{3})(.{3})(.{3})/ )
  {
    my ($u, $g, $o) = ($1, $2, $3);
    my ($sm, $um, $gm, $om) = (0, 0, 0, 0);

    $u =~ /r/ && ($um += 4);
    $u =~ /w/ && ($um += 2);
    $u =~ /x/ && ($um += 1);
    if( $u =~ /s/ ) { $um += 1; $sm += 4; }
    $u =~ /S/ && ($sm += 4);

    $g =~ /r/ && ($gm += 4);
    $g =~ /w/ && ($gm += 2);
    $g =~ /x/ && ($gm += 1);
    if( $g =~ /s/ ) { $gm += 1; $sm += 2; }
    $g =~ /S/ && ($sm += 2);

    $o =~ /r/ && ($om += 4);
    $o =~ /w/ && ($om += 2);
    $o =~ /x/ && ($om += 1);
    if( $o =~ /t/ ) { $om += 1; $sm += 1;}
    $o =~ /T/ && ($sm += 1);

    $omode = $sm . $um . $gm . $om;
  }
  return $omode;
}



sub read_devices
{
  my $tarball = shift;
  my $args;
  my %devs;

  $args = "--numeric-owner -" . $arch . "tvf " . $tarball;

  my $shell_output = <<`SHELL`;
tar $args
exit 0
SHELL

#                            | permissions               | uid/gid              | size         | date             | time           | file
# ---------------------------+---------------------------+----------------------+--------------+------------------+----------------+---------
  while( $shell_output =~ m!^([\-bcpdlrwxSsTt]{10})[ \t]+([0-9]+)/([0-9]+)[ \t]+([0-9,]+)[ \t]+([\-0-9]{10})[ \t]+([:0-9]{5})[ \t]+(.+)$!gm )
  {
    my $perm  = $1;
    my $uid   = $2;
    my $gid   = $3;
    my $size  = $4;
    my $dev   = $7;

    my ($name, $type, $smode, $mode, $owner, $major, $minor, $start, $inc, $count);

    $perm =~ s/^\s+|\s+$//g;
    $uid  =~ s/^\s+|\s+$//g;
    $gid  =~ s/^\s+|\s+$//g;
    $size =~ s/^\s+|\s+$//g;
    $dev  =~ s/^\s+|\s+$//g;

    $owner = $uid . ":" . $gid;

    $name = "/" . $dev;
    $type = substr($perm, 0, 1);
    $mode = text2oct_mode( $perm );

    $type =~ tr/-/f/;
    $smode = text2spec_mode( $perm );

    if( ($smode or 
         $type eq "b" or $type eq "c" or $type eq "s" or 
         $type eq "p" or $uid ne "0" or $gid ne "0"
        ) and $type ne "l"
      )
    {

      if( $type eq "b" or $type eq "c" )
      {
        ($major, $minor) = split( /,/, $size );
        $devs{$name} = $type . "\t" . $mode . "\t" . $uid . "\t" . $gid . "\t" . $major . "\t" . $minor;
      }
      else
      {
        $devs{$name} = $type . "\t" . $mode . "\t" . $uid . "\t" . $gid;
      }

    }
  }
  return %devs;

}


sub get_tarballs_list
{
  my @tarballs;

  if( defined $system_version and defined $distro_version and defined $distro_name )
  {
    my $init_dev_package = $products_dest_dir     .
                           "/base/init-devices-"  .
                           $system_version .  "-" .
                           $toolchain      .  "-" .
                           $distro_name    .  "-" .
                           $distro_version . ".txz";
    if( -f $init_dev_package )
    {
      push @tarballs, $init_dev_package;
    }
  }

  while( my $line = <PKGLIST_FILE> )
  {

    $line =~ /^$/ and next;
    $line =~ /^#/ and next;

    if( $line =~ m!^(.+):(.+):(.+):(.+):(.+):(.+)!gm )
    {
      my $pkg = $4;
      my $tarball = $products_dest_dir . "/" . $pkg;
      push @tarballs, $tarball;
    }
  }
  return @tarballs;
}


#
# Parse the command line options
#
$arch = 'J';
if( ! GetOptions( 'a=s' => \$arch,
                  'arch=s' => \$arch,
                  'p=s' => \$products_base_dir,
                  'products-dir=s' => \$products_base_dir,
                  'help|h|?'  => sub { usage() }
                )
  )
{
  usage();
}

# Get the rest of the command line
my $topdir = shift;

$toolchain = shift;
$hardware  = shift;
$flavour   = shift;

if( $arch eq '' )
{
  $arch = 'J';
}


if( ! defined $products_base_dir or $products_base_dir eq "" ) { $products_base_dir = "products"; }

if( ! defined $topdir    or $topdir eq "" )    { usage; }
if( ! defined $toolchain or $toolchain eq "" ) { usage; }
if( ! defined $hardware  or $hardware eq "" )  { usage; }


if( ! defined $flavour   or $flavour eq "" )
{
  $flavour = "";
  $target_build_dir  = "." . $toolchain . "/" . $hardware;
  $products_dest_dir = $topdir . "/dist/" . $products_base_dir . "/" . $toolchain . "/" . $hardware;
}
else
{
  $target_build_dir  = "." . $toolchain . "/" . $hardware . "/" . $flavour;
  $products_dest_dir = $topdir . "/dist/" . $products_base_dir . "/" . $toolchain . "/" . $hardware . "/" . $flavour;
}

# setup $top_build_dir
$top_dir = $topdir;
my $build_system = $top_dir . "/build-system";

$system_version = $ENV{SYSTEM_VERSION};
$distro_version = $ENV{DISTRO_VERSION};
$distro_name    = $ENV{DISTRO_NAME};

_kxLab::system( "mkdir -p $target_build_dir" );

#
# The HW.pkglist shoul be installed into PRODUCTS_DEST_DIR.
#
$pkglist_file = $target_build_dir . "/" . $hardware . ".pkglist";
$devices_file = $target_build_dir . "/" . ".DEVTABLE";

_kxLab::error( "build_devices_list: $topdir is not a directory" ) if( ! -d $topdir );
_kxLab::error( "build_devices_list: .pkglist missing: $pkglist_file" ) if ( ! -f $pkglist_file );


# open the intput file:
open(PKGLIST_FILE, "< $pkglist_file") or
  _kxLab::error( "$0: Could not open $pkglist_file file: $!" );
# open the output file:
open(DEVICES_FILE, "> $devices_file") or
  _kxLab::error( "build_devices_list: Could not open $devices_file file: $!" );

my @pkgs = get_tarballs_list( $pkglist_file );

# close input file:
close PKGLIST_FILE;

foreach my $pkg ( @pkgs ) { %devices = (%devices, read_devices( $pkg ) ); }

print DEVICES_FILE "# device table\n\n";
print DEVICES_FILE "# <name>\t\t<type>\t<mode>\t<uid>\t<gid>\t<major>\t<minor>\t<start>\t<inc>\t<count>\n";
foreach my $dev ( sort keys %devices )
{
  #
  # Remove the '.new' file extentsion if present:
  #
  my $fname, my @exts = qw(.new);
  my ($name, $dir, $ext) = fileparse( $dev, @exts );
  if( $ext eq ".new" ) {
    $fname = $dir . $name;
  } else {
    $fname = $dev;
  }

  print DEVICES_FILE $fname . "\t\t" .  $devices{$dev} . "\n";
}

print sprintf( "####### There are %d inodes to be created or changed.\n", scalar keys %devices );

# close output file:
close DEVICES_FILE;