[Buildroot] [scanrock 1/5] utils/scanrock: new utility for Luarocks infrastructure

Francois Perrad fperrad at gmail.com
Sun Oct 21 16:32:55 UTC 2018


Signed-off-by: Francois Perrad <francois.perrad at gadz.org>
---
 docs/manual/adding-packages-luarocks.txt |  12 ++
 utils/rockspec2br.lua                    | 238 +++++++++++++++++++++++
 utils/scanrock                           | 128 ++++++++++++
 3 files changed, 378 insertions(+)
 create mode 100644 utils/rockspec2br.lua
 create mode 100755 utils/scanrock

diff --git a/docs/manual/adding-packages-luarocks.txt b/docs/manual/adding-packages-luarocks.txt
index ec3d4e7cc..8b28c6fa8 100644
--- a/docs/manual/adding-packages-luarocks.txt
+++ b/docs/manual/adding-packages-luarocks.txt
@@ -50,6 +50,18 @@ Finally, on line 16, we invoke the +luarocks-package+
 macro that generates all the Makefile rules that actually allows the
 package to be built.
 
+Most of these data can be retrieved in the +rock+ and +rockspec+,
+which are fetched from https://luarocks.org.
+So, this file and the Config.in can be generated by running
+the script +utils/scanrock foo lua-foo+ in the Buildroot directory
+(or in a br2-external tree).
+This script creates a Config.in file and lua-foo.mk file for the
+requested package.
+You should still manually edit the result.
+
+* The +package/Config.in+ file has to be updated manually to include the
+  generated Config.in files.
+
 [[luarocks-package-reference]]
 
 ==== +luarocks-package+ reference
diff --git a/utils/rockspec2br.lua b/utils/rockspec2br.lua
new file mode 100644
index 000000000..b3bc146e6
--- /dev/null
+++ b/utils/rockspec2br.lua
@@ -0,0 +1,238 @@
+--[[
+
+Copyright (C) 2018 by Francois Perrad <francois.perrad at gadz.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+This script is a part of Buildroot.
+
+]]
+
+local function usage ()
+    print [[
+Usage:
+    utils/rockspec2br [-name foo] [-subdir foo-3.2] [-license LICENSE] foo-3.2-1.rockspec
+]]
+end
+
+local function escape (s)
+    return s:gsub('-', '%%-'):gsub('%.', '%%.')
+end
+
+local function fsname (name)
+    return name:lower():gsub('_', '-')
+end
+
+local function brname (name)
+    return name:upper():gsub('-', '_')
+end
+
+local function brlicense (license)
+    if license:match('MIT/X') then
+        return 'MIT'
+    end
+    return license
+end
+
+local function wrap (txt, max)
+    local lines = {}
+    local line = ''
+    for word in txt:gmatch('(%S+)') do
+        if line:len() + word:len() > max - 1 then
+            lines[#lines+1] = line
+            line = ''
+        end
+        if line == '' then
+            line  = word
+        else
+            line = line .. ' ' .. word
+        end
+    end
+    lines[#lines+1] = line
+    return lines
+end
+
+local br_libname = {
+   curl = 'libcurl',
+   fastcgi = 'libfcgi',
+   fuse = 'libfuse',
+   iconv = 'libiconv',
+}
+
+local function get_native_dependencies ()
+    local t = {}
+    local d = external_dependencies
+    if d then
+        if d.platforms and d.platforms.unix then
+            d = d.platforms.unix
+        end
+        for k in pairs(d) do
+            if k ~= 'platforms' then
+                k = k:lower()
+                if k ~= 'crypto' then
+                    t[#t+1] = br_libname[k] or k
+                end
+            end
+        end
+        table.sort(t)
+    end
+    return t
+end
+
+local br_name = {
+    basexx = 'lua-basexx',
+    bit32 = 'lua-bit32',
+    compat53 = 'lua-compat53',
+    cqueues = 'lua-cqueues',
+    datafile = 'lua-datafile',
+    fifo = 'lua-fifo',
+    flu = 'lua-flu',
+    http = 'lua-http',
+    lpeg_patterns = 'lua-lpeg-patterns',
+    valua = 'lua-valua',
+    sailor = 'lua-sailor',
+}
+
+local function get_dependencies ()
+    local t = {}
+    for i = 1, #dependencies do
+        local dep = dependencies[i]:match('^(%S+)')
+        if dep ~= 'lua' then
+            t[#t+1] = br_name[dep] or dep
+        end
+    end
+    table.sort(t)
+    return t
+end
+
+local function generate_config (name)
+    local only_luajit = name:match('^lj')
+    local summary = description.summary or '???'
+    local homepage = description.homepage or '???'
+    local native_dependencies = get_native_dependencies()
+    local dependencies = get_dependencies()
+    local fname = 'package/' .. name .. '/Config.in'
+    local f = assert(io.open(fname, 'w'))
+    print('write ' .. fname)
+    f:write('config BR2_PACKAGE_' .. brname(name) .. '\n')
+    f:write('\tbool "' .. name .. '"\n')
+    if only_luajit then
+        f:write('\tdepends on BR2_PACKAGE_LUAJIT\n')
+    end
+    for i = 1, #native_dependencies do
+        f:write('\tselect BR2_PACKAGE_' .. brname(native_dependencies[i]) .. '\n')
+    end
+    for i = 1, #dependencies do
+        f:write('\tselect BR2_PACKAGE_' .. brname(dependencies[i]) .. ' # runtime\n')
+    end
+    f:write('\thelp\n')
+    f:write('\t  ' .. table.concat(wrap(summary, 62), '\n\t  ') .. '\n')
+    f:write('\n\t  ' .. homepage .. '\n')
+    if only_luajit then
+        f:write('\ncomment "' .. name .. ' needs LuaJIT"\n')
+        f:write('\tdepends on !BR2_PACKAGE_LUAJIT\n')
+    end
+    f:close()
+end
+
+local function generate_mk (name, subdir, license_file)
+    local need_name_upstream = false
+    local need_version_upstream = false
+    local name_upstream = package
+    local version = version
+    local version_upstream = version:match('^([^-]+)-')
+    local revision = version:match('-(%d+)$')
+    local license = description.license
+    if subdir then
+        local root = subdir:match('^(.-)-' .. escape(version) .. '$')
+        if root then
+            subdir = root .. '-$(' .. brname(name) .. '_VERSION)'
+        end
+        root = subdir:match('^(.--[Vv])' .. escape(version_upstream) .. '$')
+        if root then
+            need_version_upstream = true
+            subdir = root .. '$(' .. brname(name) .. '_VERSION_UPSTREAM)'
+        end
+        root = subdir:match('^(.-)-' .. escape(version_upstream) .. '$')
+        if root then
+            if root == name then
+                subdir = nil
+            elseif root == name_upstream then
+                subdir = nil
+                need_name_upstream = true
+            else
+                need_version_upstream = true
+                subdir = root .. '-$(' .. brname(name) .. '_VERSION_UPSTREAM)'
+            end
+        end
+    end
+    local native_dependencies = get_native_dependencies()
+    local fname = 'package/' .. name .. '/' .. name .. '.mk'
+    local f = assert(io.open(fname, 'w'))
+    print('write ' .. fname)
+    f:write('################################################################################\n')
+    f:write('#\n')
+    f:write('# ' .. name .. '\n')
+    f:write('#\n')
+    f:write('################################################################################\n')
+    f:write('\n')
+    if need_version_upstream then
+        f:write(brname(name) .. '_VERSION_UPSTREAM = ' .. version_upstream .. '\n')
+        f:write(brname(name) .. '_VERSION = $(' .. brname(name) .. '_VERSION_UPSTREAM)-' .. revision .. '\n')
+    else
+        f:write(brname(name) .. '_VERSION = ' .. version .. '\n')
+    end
+    if name ~= name_upstream:lower() or need_name_upstream then
+        f:write(brname(name) .. '_NAME_UPSTREAM = ' .. name_upstream .. '\n')
+    end
+    if subdir then
+        f:write(brname(name) .. '_SUBDIR = ' .. subdir .. '\n')
+    end
+    if license then
+        f:write(brname(name) .. '_LICENSE = ' .. brlicense(license) .. '\n')
+    end
+    if license_file then
+        f:write(brname(name) .. '_LICENSE_FILES = $(' .. brname(name) .. '_SUBDIR)/' .. license_file .. '\n')
+    end
+    if #native_dependencies > 0 then
+        f:write(brname(name) .. '_DEPENDENCIES = ' .. table.concat(native_dependencies, ' ') .. '\n')
+    end
+    f:write('\n$(eval $(luarocks-package))\n')
+    f:close()
+end
+
+local name, subdir, license
+local i = 1
+if arg[i] == '-name' then
+    name = arg[i + 1]
+    i = i + 2
+end
+if arg[i] == '-subdir' then
+    subdir = arg[i + 1]
+    i = i + 2
+end
+if arg[i] == '-license' then
+    license = arg[i + 1]
+    i = i + 2
+end
+local rockspec = arg[i]
+if not rockspec then
+    usage()
+else
+    assert(loadfile(rockspec))()
+    name = fsname(name or package)
+    generate_config(name)
+    generate_mk(name, subdir, license)
+end
diff --git a/utils/scanrock b/utils/scanrock
new file mode 100755
index 000000000..3c13b3228
--- /dev/null
+++ b/utils/scanrock
@@ -0,0 +1,128 @@
+#!/usr/bin/env perl
+
+use 5.010;
+use strict;
+use warnings;
+use Fatal qw(open close opendir closedir);
+
+use Getopt::Long;
+use Pod::Usage;
+use Cwd;
+use Digest::SHA;
+use File::Temp qw(tempdir);
+
+my ($help, $man);
+GetOptions( 'help|?' => \$help,
+            'man' => \$man,
+) or pod2usage(-exitval => 1);
+pod2usage(-exitval => 0) if $help;
+pod2usage(-exitval => 0, -verbose => 2) if $man;
+pod2usage(-exitval => 1) if scalar @ARGV == 0;
+
+my $rockname = shift @ARGV;
+my $fsname = shift @ARGV || $rockname;
+my $cwd = getcwd();
+my $tmpdir = tempdir( CLEANUP => 1 );
+
+qx{luarocks download --source ${rockname}};
+my $rock = glob q{*.src.rock};
+
+chdir $tmpdir;
+qx{luarocks unpack ${cwd}/${rock}};
+my $unpackdir = glob q{*};
+chdir $unpackdir;
+my $rockspec = File::Spec->rel2abs( glob q{*.rockspec} );
+opendir(my $dh, q{.});
+my @subdir = grep { m|^[^\.]| && -d } readdir($dh);
+my $subdir = shift @subdir;
+closedir $dh;
+chdir $subdir;
+my @license = glob q{COPY* LICENSE* doc/LICENSE* doc/license* doc/us/license*};
+my $license = shift @license;
+chdir $cwd;
+
+if ($license) {
+    print qx{lua utils/rockspec2br.lua -name ${fsname} -subdir ${subdir} -license ${license} ${rockspec}};
+}
+else {
+    print qx{lua utils/rockspec2br.lua -name ${fsname} -subdir ${subdir} ${rockspec}};
+}
+
+my $dirname = q{package/} . $fsname;
+my $hashname = $dirname . q{/} . $fsname . q{.hash};
+mkdir $dirname unless -d $dirname;
+my $sha256 = Digest::SHA->new(256)->addfile( $rock )->hexdigest();
+say qq{write ${hashname}};
+open my $fh, q{>}, $hashname;
+say {$fh} q{# computed by scanrock};
+say {$fh} qq{sha256 ${sha256}  ${rock}};
+if ($license) {
+    $sha256 = Digest::SHA->new(256)->addfile( qq{${tmpdir}/${unpackdir}/${subdir}/${license}} )->hexdigest();
+    say {$fh} qq{sha256 ${sha256}  ${subdir}/${license}};
+}
+close $fh;
+
+unlink $rock;
+
+__END__
+
+=head1 NAME
+
+utils/scanrock foo [lua-foo]
+
+=head1 SYNOPSIS
+
+utils/scanrock [options] rockname [brname]
+
+ Options:
+   -help
+   -man
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<-help>
+
+Prints a brief help message and exits.
+
+=item B<-man>
+
+Prints the manual page and exits.
+
+=back
+
+=head1 DESCRIPTION
+
+This script creates templates of the Buildroot package files for a
+Luarock module.
+
+Most of the job is delegated to C<luarocks> and to the script
+C<utils/rockspec2br.lua>, so your $(HOST_DIR)/bin must append to PATH.
+
+After running this script, it is necessary to check the generated files.
+
+See the Buildroot documentation for details on the usage of the Luarock
+infrastructure.
+
+=head1 LICENSE
+
+Copyright (C) 2018 by Francois Perrad <francois.perrad at gadz.org>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+This script is a part of Buildroot.
+
+=cut
-- 
2.17.1




More information about the buildroot mailing list