@ -1,6 +1,7 @@
import ( " core.base.option " )
import ( " core.base.semver " )
import ( " core.base.json " )
import ( " core.base.hashset " )
import ( " lib.detect.find_tool " )
import ( " lib.detect.find_file " )
import ( " net.http " )
@ -11,174 +12,251 @@ local options = {
{ nil , " repo " , " v " , nil , " Set repository name. " ,
" e.g. " ,
" - github:xmake-io/xmake " ,
" - brew:zlib " }
" - gitlab:xmake-io/xmake " }
}
function _generate_package_from_github ( reponame )
-- get repository info
local gh = assert ( find_tool ( " gh " ) , " gh not found! " )
local repoinfo = os.iorunv ( gh.program , { " repo " , " view " , reponame , " --json " ,
" description,homepageUrl,licenseInfo,url,sshUrl,name,latestRelease " } )
-- function to get Gitlab data
function get_gitlab_data ( reponame )
local glab = assert ( find_tool ( " glab " ) , " glab not found! " )
local host = os.iorunv ( glab.program , { " config " , " get " , " host " } ) : trim ( )
local graphql_query = ' query={ project(fullPath: " ' .. reponame .. ' ") { description webUrl sshUrlToRepo name } } '
local repoinfo = os.iorunv ( glab.program , { " api " , " graphql " , " -f " , graphql_query } )
local data = { }
if repoinfo then
repoinfo = json.decode ( repoinfo )
if repoinfo.data and repoinfo.data . project then
-- extract required data and restructure it
local project_data = repoinfo.data . project
data = {
description = project_data.description ,
homepageUrl = project_data.webUrl ,
licenseInfo = " MIT " , -- NOTE: Find a way to get the project license in gitlab
url = project_data.webUrl ,
sshUrl = project_data.sshUrlToRepo ,
name = project_data.name ,
}
repoinfo.data . project = data
end
end
return { host = host , data = data }
end
local function get_github_data ( reponame )
local gh = assert ( find_tool ( " gh " ) , " gh not found! " )
local host = " github.com "
local data = os.iorunv ( gh.program , {
" repo " ,
" view " ,
reponame ,
" --json " ,
" description,homepageUrl,licenseInfo,url,sshUrl,name,latestRelease " ,
} )
if data then
data = json.decode ( data )
end
vprint ( repoinfo )
return { data = data , host = host }
end
function generate_package ( reponame , get_data )
local repo_data = get_data ( reponame )
local data = repo_data.data
local host = repo_data.host
-- generate package header
local packagename = assert ( repoinfo.name , " package name not found! " ) : lower ( )
local packagefile = path.join ( " packages " , packagename : sub ( 1 , 1 ) , packagename , " xmake.lua " )
local packagename = assert ( data .name, " package name not found! " ) : lower ( )
local packagefile = path.join ( " packages " , string.sub ( packagename , 1 , 1 ) , packagename , " xmake.lua " )
local file = io.open ( packagefile , " w " )
-- define package and homepage
file : print ( ' package("%s") ' , packagename )
local homepage = repoinfo.homepageUrl
if homepage == nil or homepage == " " then
homepage = repoinfo.url
end
local homepage = data.homepageUrl and data.homepageUrl ~= " " and data.homepageUrl or data.url
if homepage then
file : print ( ' set_homepage("%s") ' , homepage )
end
local description = repoinfo.description or ( " The " .. packagename .. " package " )
local description = data.description or ( " The " .. packagename .. " package " )
file : print ( ' set_description("%s") ' , description )
local licensekey = type ( repoinfo.licenseInfo ) == " table " and repoinfo.licenseInfo . key
if licensekey then
-- define license if available
if type ( data.licenseInfo ) == " table " and data.licenseInfo . key then
local licenses = {
[ " apache-2.0 " ] = " Apache-2.0 " ,
[ " lgpl-2.0 " ] = " LGPL-2.0 " ,
[ " lgpl-2.1 " ] = " LGPL-2.1 " ,
zlib = " zlib " ,
mit = " MIT "
mit = " MIT " ,
}
local license = licenses [ licensekey ]
local license = licenses [ data. licenseInfo . key ]
if license then
file : print ( ' set_license("%s") ' , license )
end
end
file : print ( " " )
-- generate package url s and versions
-- define package URL s and versions
local repodir
local has_xmake
local has_cmake
local has_meson
local has_bazel
local has_autoconf
local need_autogen
local latest_release = repoinfo.latestRelease
local has_xmake , has_cmake , has_meson , has_bazel , has_autoconf , need_autogen
local latest_release = data.latestRelease
if type ( latest_release ) == " table " then
local url = ( " https://github.com/%s/archive/refs/tags/%s.tar.gz " ) : format ( reponame , latest_release.tagName )
local giturl = ( " https://github.com/%s.git " ) : format ( reponame )
file : write ( ' add_urls("https://github.com/ ' .. reponame .. ' /archive/refs/tags/$(version).tar.gz", \n ' )
file : print ( ' "%s") ' , giturl )
local url = string.format ( " https://%s/%s/archive/refs/tags/%s.tar.gz " , host , reponame , latest_release.tagName )
local giturl = string.format ( " https://%s/%s.git " , host , reponame )
local tmpfile = os.tmpfile ( { ramdisk = false } ) .. " .tar.gz "
repodir = tmpfile .. " .dir "
file : write ( ' add_urls("https:// ' .. host .. ' / ' .. reponame .. ' /-/archive/$(version).tar.gz", \n ' )
file : print ( ' "%s") \n ' , giturl )
print ( " downloading %s " , url )
http.download ( url , tmpfile )
file : print ( ' add_versions("%s", "%s") ' , latest_release.tagName , hash.sha256 ( tmpfile ) )
archive.extract ( tmpfile , repodir )
os.rm ( tmpfile )
else
local giturl = ( " https://github.com/%s.git " ) : format ( reponame )
repodir = os.tmpfile ( { ramdisk = false } )
local giturl = string.format ( " git@%s:%s.git " , host , reponame )
repodir = os.tmpfile ( { ramdisk = false } )
file : print ( ' add_urls("%s") ' , giturl )
print ( " downloading %s " , giturl )
git.clone ( giturl , { outputdir = repodir , depth = 1 } )
local commit = git.lastcommit ( { repodir = repodir } )
local version = try { function ( ) return os.iorunv ( " git " , { " log " , " -1 " , " --date=format:%Y.%m.%d " , " --format=%ad " } , { curdir = repodir } ) end }
git.clone ( giturl , { outputdir = repodir , depth = 1 } )
local commit = git.lastcommit ( { repodir = repodir } )
local version = try {
function ( )
return os.iorunv ( " git " , {
" log " ,
" -1 " ,
" --date=format:%Y.%m.%d " ,
" --format=%ad " ,
} , { curdir = repodir } )
end
}
if version then
file : print ( ' add_versions("%s", "%s") ' , version : trim ( ) , commit )
end
end
local build_systems = {
[ " xmake.lua " ] = {
deps = { } ,
install = function ( configs , package )
return [ = [
io.writefile ( " xmake.lua " , [ [
add_rules ( " mode.release " , " mode.debug " )
target ( " %s " )
set_kind ( " $(kind) " )
add_files ( " src/*.c " )
add_headerfiles ( " src/(*.h) " )
] ] )
if package : config ( " shared " ) then
configs.kind = " shared "
end
import ( " package.tools.xmake " ) . install ( package , configs ) ] = ]
end ,
} ,
[ " CMakeLists.txt " ] = {
deps = { " cmake " } ,
install = function ( configs , package )
return [ [
table.insert ( configs , " -DCMAKE_BUILD_TYPE= " .. ( package : is_debug ( ) and " Debug " or " Release " ) )
table.insert ( configs , " -DBUILD_SHARED_LIBS= " .. ( package : config ( " shared " ) and " ON " or " OFF " ) )
import ( " package.tools.cmake " ) . install ( package , configs ) ] ]
end ,
} ,
[ " configure,configure.ac,autogen.sh " ] = {
deps = { " autoconf " , " automake " , " libtool " } ,
install = function ( configs , package )
return [ [
table.insert ( configs , " --enable-shared= " .. ( package : config ( " shared " ) and " yes " or " no " ) )
if package : is_debug ( ) then
table.insert ( configs , " --enable-debug " )
end
import ( " package.tools.autoconf " ) . install ( package , configs ) ] ]
end ,
} ,
[ " meson.build " ] = {
deps = { " meson " , " ninja " } ,
install = function ( configs , package )
return [ [
table.insert ( configs , " -Ddefault_library= " .. ( package : config ( " shared " ) and " shared " or " static " ) )
import ( " package.tools.meson " ) . install ( package , configs ) ] ]
end ,
} ,
[ " BUILD,BUILD.bazel " ] = {
deps = { " bazel " } ,
install = function ( configs , package )
return ' import("package.tools.bazel").install(package, configs) '
end ,
}
}
-- detect build system
local build_system = nil
if repodir then
local files = os.files ( path.join ( repodir , " * " ) ) or { }
table.join2 ( files , os.files ( path.join ( repodir , " * " , " * " ) ) )
for _ , file in ipairs ( files ) do
local filename = path.filename ( file )
if filename == " xmake.lua " then
has_xmake = true
elseif filename == " CMakeLists.txt " then
has_cmake = true
elseif filename == " configure " then
has_autoconf = true
elseif filename == " autogen.sh " or filename == " configure.ac " then
need_autogen = true
has_autoconf = true
elseif filename == " meson.build " then
has_meson = true
elseif filename == " BUILD " or filename == " BUILD.bazel " then
has_bazel = true
for k , v in pairs ( build_systems ) do
local filenames = hashset.from ( k : split ( " , " ) )
if filenames : has ( filename ) then
build_system = v
break
end
end
end
os.rm ( repodir )
end
if not build_system then
build_system = build_systems [ " xmake.lua " ]
end
-- add dependencies
if has_cmake then
file : print ( " " )
file : print ( ' add_deps("cmake") ' )
elseif has_meson then
file : print ( " " )
file : print ( ' add_deps("meson", "ninja") ' )
elseif need_autogen then
file : print ( " " )
file : print ( ' add_deps("autoconf", "automake", "libtool") ' )
elseif has_bazel then
file : print ( " " )
file : print ( ' add_deps("bazel") ' )
if build_system then
file : print ( ' ' )
local deps = table.wrap ( build_system.deps )
if deps and # deps > 0 then
file : print ( ' add_deps(" ' .. table.concat ( deps , ' ", " ' ) .. ' ") ' )
end
end
-- generate install scripts
file : print ( " " )
file : print ( " on_install(function (package) " )
file : print ( " local configs = {} " )
if has_cmake then
file : print ( ' table.insert(configs, "-DCMAKE_BUILD_TYPE=" .. (package:debug() and "Debug" or "Release")) ' )
file : print ( ' table.insert(configs, "-DBUILD_SHARED_LIBS=" .. (package:config("shared") and "ON" or "OFF")) ' )
file : print ( ' import("package.tools.cmake").install(package, configs) ' )
elseif has_autoconf then
file : print ( ' table.insert(configs, "--enable-shared=" .. (package:config("shared") and "yes" or "no")) ' )
file : print ( ' if package:debug() then ' )
file : print ( ' table.insert(configs, "--enable-debug") ' )
file : print ( ' end ' )
file : print ( ' import("package.tools.autoconf").install(package, configs) ' )
elseif has_meson then
file : print ( ' table.insert(configs, "-Ddefault_library=" .. (package:config("shared") and "shared" or "static")) ' )
file : print ( ' import("package.tools.meson").install(package, configs) ' )
elseif has_bazel then
file : print ( ' import("package.tools.bazel").install(package, configs) ' )
else
file : print ( ' io.writefile("xmake.lua", [[ ' )
file : print ( ' add_rules("mode.release", "mode.debug") ' )
file : print ( ' target("%s") ' , packagename )
file : write ( ' set_kind("$(kind)") \n ' )
file : print ( ' add_files("src/*.c") ' )
file : print ( ' add_headerfiles("src/(*.h)") ' )
file : print ( ' ]]) ' )
file : print ( ' if package:config("shared") then ' )
file : print ( ' configs.kind = "shared" ' )
file : print ( ' end ' )
file : print ( ' import("package.tools.xmake").install(package, configs) ' )
file : print ( ' ' )
file : print ( ' on_install(function (package) ' )
file : print ( ' local configs = {} ' )
if build_system then
file : print ( build_system.install ( configs , package ) )
end
file : print ( " end) " )
file : print ( ' end) ' )
-- generate test scripts
file : print ( " " )
file : print ( " on_test(function (package) " )
file : print ( ' ' )
file : print ( ' on_test(function (package) ' )
file : print ( ' assert(package:has_cfuncs("foo", {includes = "foo.h"})) ' )
file : print ( " end) " )
file : print ( ' end) ' )
file : close ( )
io.cat ( packagefile )
cprint ( " ${bright}%s generated! " , packagefile )
end
function main ( ... )
local opt = option.parse ( table.pack ( ... ) , options , " New a package. " , " " ,
" Usage: xmake l scripts/new.lua [options] " )
local repo = opt.repo
if repo and repo : startswith ( " github: " ) then
_generate_package_from_github ( repo : sub ( 8 ) )
else
raise ( " we need set repository name first! " )
local opt = option.parse ( table.pack ( ... ) , options , " New a package. " , " " , " Usage: xmake l scripts/new.lua [options] " )
local repo = assert ( opt.repo , " repository name must be set! " )
local reponame = repo : sub ( 8 )
if repo : startswith ( " github: " ) then
generate_package ( reponame , get_github_data )
return
end
if repo : startswith ( " gitlab: " ) then
generate_package ( reponame , get_gitlab_data )
return
end
raise ( " unsupported repository source. only 'github' and 'gitlab' are supported. " )
end