Everywhere: Rename package "jw-build" to "jw-pkg"
jw-build doesn't stop at building software, packaging it afterwards is also a core feature, so this commit gives the package a better name. The commit replaces strings s/jw-build/jw-pkg/ in text files and file names. Fallout to the functionality is fixed, variable names are left as they are, though. To be adjusted by later commits. Signed-off-by: Jan Lindemann <jan@janware.com>
This commit is contained in:
parent
ca95a9d6b2
commit
9217d38964
50 changed files with 36 additions and 36 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -4,7 +4,7 @@ bin/*.py
|
|||
*.done
|
||||
*.dist
|
||||
make/.cache.mk
|
||||
make/jw-build.pc
|
||||
make/jw-pkg.pc
|
||||
minimal-to-master.sh
|
||||
pkg-build.dist
|
||||
pkgconfig/
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ else ifeq ($(COMPILER_SUITE),clang)
|
|||
|
||||
endif # COMPILER_SUITE
|
||||
|
||||
# -- jw-build variables based on arch and toolchain
|
||||
# -- jw-pkg variables based on arch and toolchain
|
||||
|
||||
ifeq ($(TARGET_TRIPLET),arm-none-eabi)
|
||||
LIBTYPE ?= static
|
||||
|
|
@ -514,7 +514,7 @@ ifeq ($(USE_PROJECT_LIB),true)
|
|||
PROJECTLIB_LDFLAGS += -L$(TOPDIR)/lib -l$(LIBNAME)
|
||||
endif
|
||||
|
||||
ifneq ($(filter jw-build,$(PREREQ_BUILD)),)
|
||||
ifneq ($(filter jw-pkg,$(PREREQ_BUILD)),)
|
||||
ifeq ($(TARGET),mingw)
|
||||
JW_FINAL_LDFLAGS += -lglib-2.0 -lws2_32 -lstdc++
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# jw-build library
|
||||
# jw-pkg library
|
||||
# (c) 2001 jannet it services
|
||||
# contact@jannet.de
|
||||
# $Id$
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# jw-build library
|
||||
# jw-pkg library
|
||||
# (c) 2001 jannet it services
|
||||
# contact@jannet.de
|
||||
# $Id$
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ ifeq ($(USE_USER_URL),true)
|
|||
endif
|
||||
|
||||
SUBMOD_SRC_DIR ?= .
|
||||
GIT_SRV_ADMIN_SH = ssh $(JANWARE_USER_PREFIX)git.janware.com /opt/jw-build/bin/git-srv-admin.sh
|
||||
GIT_SRV_ADMIN_SH = ssh $(JANWARE_USER_PREFIX)git.janware.com /opt/jw-pkg/bin/git-srv-admin.sh
|
||||
GIT_REPO_URL = ssh://$(JANWARE_USER_PREFIX)git.janware.com/srv/git/$(JANWARE_USER)/contrib/$(SUBMOD_PKG_NAME)
|
||||
SUBMOD_PATH = $(patsubst $(abspath $(TOPDIR))/%,%,$(abspath $(CWD)/$(SUBMOD_SRC_DIR)))
|
||||
SUB_GIT = git -C $(SUBMOD_SRC_DIR)
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ else
|
|||
endif
|
||||
SYSTEM_LIBDIR = /usr/$(SYSTEM_LIBDIR_NAME)
|
||||
|
||||
# - support legacy jw-build target variables
|
||||
# - support legacy jw-pkg target variables
|
||||
ifneq ($(findstring $(TARGET_ABI),mingw mingw32 mingw64),)
|
||||
TARGET ?= mingw
|
||||
else
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# (C) Copyright 2001-2025, Jan Lindemann <jan@janware.com>
|
||||
#
|
||||
# This is the top-level Makefile for a software build tree organized by
|
||||
# jw-build. It is provided under the terms of the GNU Lesser Public License,
|
||||
# jw-pkg. It is provided under the terms of the GNU Lesser Public License,
|
||||
# Version 2.
|
||||
#
|
||||
# Current documentation on how this Makefile is meant to be used can be found
|
||||
|
|
@ -17,7 +17,7 @@ PROJECTS_MAKEFILE_NAME := $(firstword $(MAKEFILE_LIST))
|
|||
|
||||
-include local.mk
|
||||
|
||||
JWBDIR ?= jw-build
|
||||
JWBDIR ?= jw-pkg
|
||||
|
||||
ifeq ($(origin PROJECTS_DIR_REMOTE_BASE),undefined)
|
||||
ifneq ($(wildcard $(JWBDIR)),)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# (C) Copyright 2001-2025, Jan Lindemann <jan@janware.com>
|
||||
#
|
||||
# This is the top-level Makefile for a software build tree organized by
|
||||
# jw-build. It is provided under the terms of the GNU Lesser Public License,
|
||||
# jw-pkg. It is provided under the terms of the GNU Lesser Public License,
|
||||
# Version 2.
|
||||
#
|
||||
# Current documentation on how this Makefile is meant to be used can be found
|
||||
|
|
@ -21,13 +21,13 @@ PROJECTS_MAKEFILE_NAME ?= $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)
|
|||
|
||||
# -- Find JWBDIR
|
||||
DEV_PROJECTS_DIR ?= .
|
||||
JWBDIR_NAME ?= jw-build
|
||||
JWBDIR_NAME ?= jw-pkg
|
||||
JWBDIR_SEARCH_PATH ?= $(DEV_PROJECTS_DIR) $(BUILD_TOOLS_PREFIX)/opt/$(FLAVOUR_PATH_PREFIX)
|
||||
JWBDIR ?= $(firstword $(wildcard $(addsuffix /$(JWBDIR_NAME),$(JWBDIR_SEARCH_PATH))))
|
||||
|
||||
JW_BUILD_BINDIR = $(JWBDIR)/bin
|
||||
JWB_SCRIPT_DIR = $(firstword $(wildcard ./$(JWBDIR_NAME)/scripts $(JW_BUILD_BINDIR)) jwb-script-dir-not-found)
|
||||
JW_BUILD_REMOTE_BINDIR = /opt/jw-build/bin
|
||||
JW_BUILD_REMOTE_BINDIR = /opt/jw-pkg/bin
|
||||
|
||||
SHELL = /bin/bash -o pipefail +H
|
||||
PROJECTS_TXT ?= projects.txt
|
||||
|
|
@ -89,7 +89,7 @@ else
|
|||
endif
|
||||
|
||||
ifeq ($(filter pkg-%,$(MAKECMDGOALS)),)
|
||||
JW_BUILD_SSH_EXTRA_OPTS += -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/%r@jw-build:%h:%p -o ControlPersist=3m
|
||||
JW_BUILD_SSH_EXTRA_OPTS += -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=/tmp/%r@jw-pkg:%h:%p -o ControlPersist=3m
|
||||
ifneq ($(JANWARE_USER),)
|
||||
JW_BUILD_SSH_EXTRA_OPTS += -l $(JANWARE_USER)
|
||||
endif
|
||||
|
|
@ -137,7 +137,7 @@ endif
|
|||
|
||||
PURGE_SH = /bin/bash $(firstword $(wildcard $(JWB_SCRIPT_DIR)/purge-stale-projects.sh $(JW_BUILD_BINDIR)/purge-stale-projects.sh) purge-not-found)
|
||||
PKG_MANAGER_SH ?= /bin/bash $(firstword $(wildcard $(JWB_SCRIPT_DIR)/pkg-manager.sh $(JW_BUILD_BINDIR)/pkg-manager.sh) pkg-manager-not-found)
|
||||
CREATE_PROJECT_SH ?= /bin/bash $(firstword $(wildcard $(JWB_SCRIPT_DIR)/jw-build-create-project.sh $(JW_BUILD_BINDIR)/jw-build-create-project.sh) jw-build-create-project-not-found)
|
||||
CREATE_PROJECT_SH ?= /bin/bash $(firstword $(wildcard $(JWB_SCRIPT_DIR)/jw-pkg-create-project.sh $(JW_BUILD_BINDIR)/jw-pkg-create-project.sh) jw-pkg-create-project-not-found)
|
||||
LIST_VCS_FILES_SH = /bin/bash $(firstword $(wildcard $(JWB_SCRIPT_DIR)/scm.sh $(JW_BUILD_BINDIR)/scm.sh) scm-sh-not-found) ls-files
|
||||
GIT_SRV_ADMIN_SH = JW_BUILD_SSH_EXTRA_OPTS="$(JW_BUILD_SSH_EXTRA_OPTS)" $(GIT_SSH) $(JANWARE_USER)@git.janware.com $(JW_BUILD_REMOTE_BINDIR)/git-srv-admin.sh
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ GIT_DESCR = $(TOPDIR)/.git/description
|
|||
GIT_MAIN_BRANCH ?= master
|
||||
|
||||
OPT_JANWARE_PROJECT ?= -j
|
||||
PKG_MANAGER_SH ?= /bin/bash $(firstword $(wildcard $(JWB_SCRIPT_DIR)/pkg-manager.sh /opt/jw-build/bin/pkg-manager.sh) pkg-manager-not-found)
|
||||
PKG_MANAGER_SH ?= /bin/bash $(firstword $(wildcard $(JWB_SCRIPT_DIR)/pkg-manager.sh /opt/jw-pkg/bin/pkg-manager.sh) pkg-manager-not-found)
|
||||
|
||||
ifeq ($(OPT_JANWARE_PROJECT),-j)
|
||||
REMOTE_GIT_FLAVOUR ?= proj
|
||||
|
|
@ -144,7 +144,7 @@ git-config:
|
|||
git remote -v | grep -q "^origin *$(REMOTE_GIT_URL)" || git remote set-url --push origin $(REMOTE_GIT_URL)
|
||||
|
||||
git-clone-to-remote:
|
||||
ssh $(JANWARE_USER)@git.janware.com "/opt/jw-build/bin/git-srv-admin.sh $(OPT_JANWARE_PROJECT) create-personal-project $(PROJECT)"
|
||||
ssh $(JANWARE_USER)@git.janware.com "/opt/jw-pkg/bin/git-srv-admin.sh $(OPT_JANWARE_PROJECT) create-personal-project $(PROJECT)"
|
||||
make git-config
|
||||
git push --set-upstream origin $(GIT_MAIN_BRANCH)
|
||||
git push --all $(REMOTE_GIT_URL)
|
||||
|
|
@ -160,7 +160,7 @@ git-init-remote: git-import git-clone-to-remote
|
|||
git-descr: $(GIT_DESCR)
|
||||
|
||||
git-update-project-description:
|
||||
ssh $(JANWARE_USER)@git.janware.com "/opt/jw-build/bin/git-srv-admin.sh $(OPT_JANWARE_PROJECT) update-descriptions $(PROJECT)"
|
||||
ssh $(JANWARE_USER)@git.janware.com "/opt/jw-pkg/bin/git-srv-admin.sh $(OPT_JANWARE_PROJECT) update-descriptions $(PROJECT)"
|
||||
|
||||
projects-%:
|
||||
$(PYTHON) $(JWB_SCRIPT_DIR)/jw-projects.py build $* $(PROJECT)
|
||||
|
|
|
|||
197
scripts/jw-pkg-create-project.sh
Normal file
197
scripts/jw-pkg-create-project.sh
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
#!/bin/bash
|
||||
|
||||
log()
|
||||
{
|
||||
echo $@
|
||||
}
|
||||
|
||||
err()
|
||||
{
|
||||
log $@
|
||||
}
|
||||
|
||||
fatal()
|
||||
{
|
||||
err $@
|
||||
exit 1
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "$myname [-h] [-s summary] [-d description] [-g pkg-group] name"
|
||||
[ "$1" ] && exit $1
|
||||
}
|
||||
|
||||
cat_Makefile()
|
||||
{
|
||||
cat <<-EOT
|
||||
TOPDIR = .
|
||||
|
||||
include \$(TOPDIR)/make/proj.mk
|
||||
include \$(JWBDIR)/make/topdir.mk
|
||||
EOT
|
||||
}
|
||||
|
||||
cat_VERSION()
|
||||
{
|
||||
cat <<-EOT
|
||||
1.0.0-0-dev
|
||||
EOT
|
||||
}
|
||||
|
||||
cat_make_Makefile()
|
||||
{
|
||||
cat <<-EOT
|
||||
TOPDIR = ..
|
||||
|
||||
include \$(TOPDIR)/make/proj.mk
|
||||
include \$(JWBDIR)/make/make.mk
|
||||
EOT
|
||||
}
|
||||
|
||||
cat_make_proj_mk()
|
||||
{
|
||||
cat <<-EOT
|
||||
# to be included from inside the project directory
|
||||
|
||||
DEV_PROJECTS_DIR ?= \$(TOPDIR)/..
|
||||
ifeq (\$(TARGET),mingw)
|
||||
FLAVOUR_PATH_PREFIX = win32/
|
||||
endif
|
||||
JWBDIR ?= \$(firstword \$(wildcard \$(DEV_PROJECTS_DIR)/jw-pkg \$(BUILD_TOOLS_PREFIX)/opt/\$(FLAVOUR_PATH_PREFIX)jw-pkg))
|
||||
|
||||
USE_PROJECT_LIB = false
|
||||
HDRDIR_SCOPE_SUFFIX = \$(PROJECT)
|
||||
EOT
|
||||
}
|
||||
|
||||
cat_make_project_conf()
|
||||
{
|
||||
local login=$JANWARE_USER
|
||||
[ "$login" ] || login=`whoami`
|
||||
|
||||
local fullname=`getent passwd $login | cut -d: -f5`
|
||||
[ "$fullname" ] || fullname=$JANWARE_USER
|
||||
[ "$fullname" ] || fullname=`whoami | xargs getent passwd | cut -d: -f5`
|
||||
[ "$fullname" ] || fullname=`whoami`
|
||||
|
||||
cat <<-EOT
|
||||
[summary]
|
||||
$summary
|
||||
|
||||
[description]
|
||||
$description
|
||||
|
||||
[global]
|
||||
group = "$pkg_group"
|
||||
subpackages = $subpackages
|
||||
license = Copyright (c) $fullname, all rights reserved
|
||||
jw-maintainer = $JANWARE_USER
|
||||
|
||||
[build]
|
||||
libname = none
|
||||
|
||||
[pkg.requires.jw]
|
||||
devel = $name-run = VERSION-REVISION, jw-pkg-devel = VERSION
|
||||
build = jw-pkg-devel
|
||||
EOT
|
||||
}
|
||||
|
||||
cat_gitignore()
|
||||
{
|
||||
cat <<-EOT
|
||||
*.done
|
||||
*.dist
|
||||
*.dep.mk
|
||||
.cache.mk
|
||||
*.o
|
||||
*.so.*
|
||||
*.so
|
||||
*.a
|
||||
*.rep
|
||||
ld-*.conf
|
||||
*.ldscript
|
||||
*.pc
|
||||
$name
|
||||
*_generated_*
|
||||
*.secret
|
||||
local.mk
|
||||
.gdb_history
|
||||
dist
|
||||
mkspec.sh
|
||||
*.out
|
||||
*.orig
|
||||
*.old
|
||||
.feedfs_history
|
||||
.exrc
|
||||
*.swp
|
||||
*tmp*
|
||||
__init__.py
|
||||
__pycache__
|
||||
EOT
|
||||
}
|
||||
|
||||
# ---------------------- here we go
|
||||
|
||||
myname=`basename $0`
|
||||
projdir=.
|
||||
|
||||
summary=
|
||||
description=
|
||||
subpackages="run"
|
||||
|
||||
eval set -- `getopt -- hd:s:p:g: "$@"`
|
||||
|
||||
while [ "$1" != -- ]; do
|
||||
case $1 in
|
||||
-d)
|
||||
eval description=\"$2\"
|
||||
shift;;
|
||||
-s)
|
||||
eval summary=\"$2\"
|
||||
shift;;
|
||||
-p)
|
||||
eval subpackages=\"$2\"
|
||||
shift;;
|
||||
-g)
|
||||
eval pkg_group=\"$2\"
|
||||
shift;;
|
||||
-h)
|
||||
usage 0;;
|
||||
*)
|
||||
usage 1;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
shift
|
||||
|
||||
[ -z "$description" ] && description="$summary"
|
||||
[ -z "$summary" ] && summary="$description"
|
||||
[ -z "$pkg_group" ] && pkg_group="Amusements/Teaching/Other"
|
||||
|
||||
[ -f $projdir/Makefile ] || {
|
||||
fatal "$projdir doesn't contain a Makefile"
|
||||
}
|
||||
|
||||
name="$1"
|
||||
|
||||
[ -d $projdir/$name ] && {
|
||||
fatal "$projdir/$name already exists"
|
||||
}
|
||||
|
||||
set -e
|
||||
|
||||
mkdir -p $projdir
|
||||
mkdir $name
|
||||
cd $projdir/$name
|
||||
|
||||
mkdir make
|
||||
cat_Makefile > Makefile
|
||||
cat_make_Makefile > make/Makefile
|
||||
cat_VERSION > VERSION
|
||||
cat_make_proj_mk > make/proj.mk
|
||||
cat_make_project_conf > make/project.conf
|
||||
cat_gitignore > .gitignore
|
||||
|
||||
log Successfully created project template \"$name\".
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from jw.build.App import App
|
||||
from jw.pkg.App import App
|
||||
|
||||
App().run()
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ clone()
|
|||
local toref="${refspec[2]}"
|
||||
[ "$fromuser" ] || fromuser=$whoami
|
||||
[ "$fromref" ] || fromref=master
|
||||
local git_srv_admin="$SSH $login@git.janware.com /opt/jw-build/bin/git-srv-admin.sh"
|
||||
local git_srv_admin="$SSH $login@git.janware.com /opt/jw-pkg/bin/git-srv-admin.sh"
|
||||
|
||||
if [ -z "$projects" ]; then
|
||||
projects=`$jw_projects list-repos --from-user $fromuser $remote_base`
|
||||
|
|
|
|||
|
|
@ -547,7 +547,7 @@ upload_file()
|
|||
;;
|
||||
*)
|
||||
target=$target_base/rpm/$t/$f:$upload_attrib
|
||||
#/srv/ftp/pub/packages/jw-foss/suse/tumbleweed/rpm/src/jw-build-1.0.0-74.src.rpm
|
||||
#/srv/ftp/pub/packages/jw-foss/suse/tumbleweed/rpm/src/jw-pkg-1.0.0-74.src.rpm
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
|
@ -559,7 +559,7 @@ upload_file()
|
|||
;;
|
||||
*)
|
||||
target=$target_base/rpm/$t/$f:$upload_attrib
|
||||
#/srv/ftp/pub/packages/jw-foss/suse/tumbleweed/rpm/x86_64/jw-build-run-1.0.0-74.x86_64.rpm
|
||||
#/srv/ftp/pub/packages/jw-foss/suse/tumbleweed/rpm/x86_64/jw-pkg-run-1.0.0-74.x86_64.rpm
|
||||
;;
|
||||
esac
|
||||
esac
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ done
|
|||
local_cvs_proj=`ls -d */CVS 2>/dev/null | sed 's%/[^/]*%%'`
|
||||
local_git_proj=`ls -d */.git 2>/dev/null | sed 's%/[^/]*%%'`
|
||||
remote_cvs_proj=`$ssh cvs.janware.com find /srv/cvs/proj -maxdepth 1 -mindepth 1 -type d -executable -readable | sed 's%.*/%%'`
|
||||
remote_git_proj=`$ssh git.janware.com /opt/jw-build/bin/git-srv-admin.sh -j list-personal-projects`
|
||||
remote_git_proj=`$ssh git.janware.com /opt/jw-pkg/bin/git-srv-admin.sh -j list-personal-projects`
|
||||
|
||||
date=`date +'%Y%m%d'`
|
||||
myname=`basename $0`
|
||||
|
|
|
|||
466
src/python/jw/pkg/App.py
Normal file
466
src/python/jw/pkg/App.py
Normal file
|
|
@ -0,0 +1,466 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# This source code file is a merge of various build tools and a horrible mess.
|
||||
#
|
||||
|
||||
import os, sys, argparse, pwd, re
|
||||
|
||||
# meaning of pkg.requires.xxx variables
|
||||
# build: needs to be built and installed before this can be built
|
||||
# devel: needs to be installed before this-devel can be installed, i.e. before _other_ packages can be built against this
|
||||
# run: needs to be installed before this-run can be installed, i.e. before this and other packages can run with this
|
||||
|
||||
# --------------------------------------------------------------------- helpers
|
||||
|
||||
class ResultCache(object):
|
||||
|
||||
def __init__(self):
|
||||
self.__cache = {}
|
||||
|
||||
def run(self, func, args):
|
||||
d = self.__cache
|
||||
depth = 0
|
||||
keys = [ func.__name__ ] + args
|
||||
l = len(keys)
|
||||
for k in keys:
|
||||
if k is None:
|
||||
k = 'None'
|
||||
else:
|
||||
k = str(k)
|
||||
depth += 1
|
||||
#self.projects.debug('depth = ', depth, 'key = ', k, 'd = ', str(d))
|
||||
if k in d:
|
||||
if l == depth:
|
||||
return d[k]
|
||||
d = d[k]
|
||||
continue
|
||||
if l == depth:
|
||||
r = func(*args)
|
||||
d[k] = r
|
||||
return r
|
||||
d = d[k] = {}
|
||||
#d = d[k]
|
||||
raise Exception("cache algorithm failed for function", func.__name__, "in depth", depth)
|
||||
|
||||
# ----------------------------------------------------------------- class App
|
||||
|
||||
class App(object):
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.global_args = []
|
||||
self.opt_os = None
|
||||
self.top_name = None
|
||||
self.glob_os_cascade = None
|
||||
|
||||
self.dep_cache = {}
|
||||
self.my_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
self.opt_debug = False
|
||||
self.res_cache = ResultCache()
|
||||
self.topdir = None
|
||||
self.projs_root = os.path.expanduser("~") + '/local/src/jw.dev/proj'
|
||||
|
||||
def debug(self, *objs):
|
||||
if self.opt_debug:
|
||||
print("DEBUG: ", *objs, file = sys.stderr)
|
||||
|
||||
def warn(self, *objs):
|
||||
print("WARNING: ", *objs, file = sys.stderr)
|
||||
|
||||
def err(self, *objs):
|
||||
print("ERR: ", *objs, file = sys.stderr)
|
||||
|
||||
def proj_dir(self, name):
|
||||
if name == self.top_name:
|
||||
return self.topdir
|
||||
for d in [ self.projs_root, '/opt' ]:
|
||||
r = d + '/' + name
|
||||
if os.path.exists(r):
|
||||
return r
|
||||
if os.path.exists(f'/usr/share/doc/packages/{name}/VERSION'):
|
||||
# The package exists but does not have a dedicated project directory
|
||||
return None
|
||||
raise Exception('No project path found for module "{}"'.format(name))
|
||||
|
||||
def re_section(self, name):
|
||||
return re.compile('[' + name + ']'
|
||||
'.*?'
|
||||
'(?=[)',
|
||||
re.DOTALL)
|
||||
|
||||
def remove_duplicates(self, seq):
|
||||
seen = set()
|
||||
seen_add = seen.add
|
||||
return [x for x in seq if not (x in seen or seen_add(x))]
|
||||
|
||||
def get_os(self, args = ""):
|
||||
import subprocess
|
||||
for d in [ self.projs_root + '/jw-pkg/scripts', '/opt/jw-pkg/bin' ]:
|
||||
script = d + '/get-os.sh'
|
||||
if os.path.isfile(script):
|
||||
cmd = '/bin/bash ' + script
|
||||
if args:
|
||||
cmd = cmd + ' ' + args
|
||||
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
|
||||
(out, rr) = p.communicate()
|
||||
if rr:
|
||||
self.err("failed to run ", cmd)
|
||||
continue
|
||||
out = re.sub('\n', '', out.decode('utf-8'))
|
||||
return out
|
||||
return "linux"
|
||||
|
||||
# TODO: add support for customizing this in project.conf
|
||||
def htdocs_dir(self, name):
|
||||
pd = self.proj_dir(name)
|
||||
if pd is None:
|
||||
return None
|
||||
for r in [ pd + "/tools/html/htdocs", pd + "/htdocs", "/srv/www/proj/" + name ]:
|
||||
if os.path.isdir(r):
|
||||
return r
|
||||
return None
|
||||
|
||||
def os_cascade(self):
|
||||
import platform
|
||||
if self.glob_os_cascade is not None:
|
||||
return self.glob_os_cascade.copy()
|
||||
r = [ 'os', platform.system().lower() ]
|
||||
os = self.opt_os if self.opt_os is not None else self.res_cache.run(self.get_os, [])
|
||||
name = re.sub('-.*', '', os)
|
||||
series = os
|
||||
while True:
|
||||
n = re.sub(r'\.[0-9]+$', '', series)
|
||||
if n == series:
|
||||
break
|
||||
r.append(n)
|
||||
series = n
|
||||
if not name in r:
|
||||
r.append(name)
|
||||
if not os in r:
|
||||
r.append(os)
|
||||
# e.g. os, linux, suse, suse-tumbleweed
|
||||
#return [ 'os', platform.system().lower(), name, os ]
|
||||
self.glob_os_cascade = r
|
||||
return r
|
||||
|
||||
def strip_module_from_spec(self, mod):
|
||||
return re.sub(r'-dev$|-devel$|-run$', '', re.split('([=><]+)', mod)[0].strip())
|
||||
|
||||
def get_section(self, path, section):
|
||||
r = ''
|
||||
file = open(path)
|
||||
pat = '[' + section + ']'
|
||||
in_section = False
|
||||
for line in file:
|
||||
if (line.rstrip() == pat):
|
||||
in_section = True
|
||||
continue
|
||||
if in_section:
|
||||
if len(line) and line[0] == '[':
|
||||
break
|
||||
r = r + line
|
||||
file.close()
|
||||
return r.rstrip()
|
||||
|
||||
def read_value(self, path, section, key):
|
||||
|
||||
def scan_section(f, key):
|
||||
if key is None:
|
||||
r = ''
|
||||
for line in f:
|
||||
if len(line) and line[0] == '[':
|
||||
break
|
||||
r += line
|
||||
return r if len(r) else None
|
||||
lines = []
|
||||
cont_line = ''
|
||||
for line in f:
|
||||
if len(line) and line[0] == '[':
|
||||
break
|
||||
cont_line += line.rstrip()
|
||||
if len(cont_line) and cont_line[-1] == '\\':
|
||||
cont_line = cont_line[0:-1]
|
||||
continue
|
||||
lines.append(cont_line)
|
||||
cont_line = ''
|
||||
for line in lines:
|
||||
#self.debug(" looking for >%s< in line=>%s<" % (key, line))
|
||||
rr = re.findall('^ *' + key + ' *= *(.*)', line)
|
||||
if len(rr) > 0:
|
||||
return rr[0]
|
||||
return None
|
||||
|
||||
def scan_section_debug(f, key):
|
||||
rr = scan_section(f, key)
|
||||
#self.debug(" returning", rr)
|
||||
return rr
|
||||
|
||||
try:
|
||||
#self.debug("looking for {}::[{}].{}".format(path, section, key))
|
||||
with open(path, 'r') as f:
|
||||
if not len(section):
|
||||
rr = scan_section(f, key)
|
||||
pat = '[' + section + ']'
|
||||
for line in f:
|
||||
if line.rstrip() == pat:
|
||||
return scan_section(f, key)
|
||||
return None
|
||||
except:
|
||||
self.debug(path, "not found")
|
||||
# TODO: handle this special case cleaner somewhere up the stack
|
||||
if section == 'build' and key == 'libname':
|
||||
return 'none'
|
||||
return None
|
||||
|
||||
def get_value(self, name, section, key):
|
||||
self.debug("getting value [%s].%s for project %s (%s)" %(section, key, name, self.top_name))
|
||||
if self.top_name and name == self.top_name:
|
||||
proj_root = self.topdir
|
||||
else:
|
||||
proj_root = self.projs_root + '/' + name
|
||||
self.debug("proj_root = " + proj_root)
|
||||
|
||||
if section == 'version':
|
||||
proj_version_dirs = [ proj_root ]
|
||||
if proj_root != self.topdir:
|
||||
proj_version_dirs.append('/usr/share/doc/packages/' + name)
|
||||
for d in proj_version_dirs:
|
||||
version_path = d + '/VERSION'
|
||||
try:
|
||||
with open(version_path) as fd:
|
||||
r = fd.read().replace('\n', '').replace('-dev', '')
|
||||
fd.close()
|
||||
return r
|
||||
except EnvironmentError:
|
||||
self.debug("ignoring unreadable file " + version_path)
|
||||
continue
|
||||
raise Exception("No version file found for project \"" + name + "\"")
|
||||
|
||||
path = proj_root + '/make/project.conf'
|
||||
#print('path = ', path, 'self.top_name = ', self.top_name, 'name = ', name)
|
||||
return self.res_cache.run(self.read_value, [path, section, key])
|
||||
|
||||
def collect_values(self, names, section, key):
|
||||
r = ""
|
||||
for n in names:
|
||||
val = self.get_value(n, section, key)
|
||||
if val:
|
||||
r = r + " " + val
|
||||
return self.remove_duplicates([x.strip() for x in r.split(",")])
|
||||
|
||||
# scope 0: no children
|
||||
# scope 1: children
|
||||
# scope 2: recursive
|
||||
|
||||
def add_modules_from_project_txt_cached(self, buf, visited, spec, section, key, add_self, scope,
|
||||
names_only):
|
||||
return self.res_cache.run(self.add_modules_from_project_txt, [buf, visited, spec, section, key,
|
||||
add_self, scope, names_only])
|
||||
|
||||
def add_modules_from_project_txt(self, buf, visited, spec, section, key, add_self, scope,
|
||||
names_only):
|
||||
name = self.strip_module_from_spec(spec)
|
||||
if names_only:
|
||||
spec = name
|
||||
if spec in buf:
|
||||
return
|
||||
if spec in visited:
|
||||
if add_self:
|
||||
buf.append(spec)
|
||||
return
|
||||
visited.add(spec)
|
||||
deps = self.get_value(name, section, key)
|
||||
self.debug("name = ", name, "section = ", section, "key = ", key, "deps = ", deps, "scope = ", scope, "visited = ", visited)
|
||||
if deps and scope > 0:
|
||||
if scope == 1:
|
||||
subscope = 0
|
||||
else:
|
||||
subscope = 2
|
||||
deps = deps.split(',')
|
||||
for dep in deps:
|
||||
dep = dep.strip()
|
||||
if not(len(dep)):
|
||||
continue
|
||||
self.add_modules_from_project_txt_cached(buf, visited, dep,
|
||||
section, key, add_self=True, scope=subscope,
|
||||
names_only=names_only)
|
||||
if add_self:
|
||||
buf.append(spec)
|
||||
|
||||
def get_modules_from_project_txt(self, names, sections, keys, add_self, scope,
|
||||
names_only = True):
|
||||
if isinstance(keys, str):
|
||||
keys = [ keys ]
|
||||
#r = set()
|
||||
r = []
|
||||
for section in sections:
|
||||
for key in keys:
|
||||
visited = set()
|
||||
for name in names:
|
||||
rr = []
|
||||
self.add_modules_from_project_txt_cached(rr, visited, name, section, key, add_self, scope,
|
||||
names_only)
|
||||
# TODO: this looks like a performance hogger
|
||||
for m in rr:
|
||||
if not m in r:
|
||||
r.append(m)
|
||||
return r
|
||||
|
||||
def get_libname(self, names):
|
||||
vals = self.get_modules_from_project_txt(names, ['build'], 'libname',
|
||||
scope = 1, add_self=False, names_only=True)
|
||||
if not vals:
|
||||
return ' '.join(names)
|
||||
if 'none' in vals:
|
||||
vals.remove('none')
|
||||
return ' '.join(reversed(vals))
|
||||
|
||||
def is_excluded_from_build(self, module):
|
||||
self.debug("checking if module " + module + " is excluded from build")
|
||||
exclude = self.get_modules_from_project_txt([ module ], ['build'], 'exclude',
|
||||
scope = 1, add_self=False, names_only=True)
|
||||
cascade = self.os_cascade() + [ 'all' ]
|
||||
for p1 in exclude:
|
||||
for p2 in cascade:
|
||||
if p1 == p2:
|
||||
return p1
|
||||
return None
|
||||
|
||||
# -L needs to contain more paths than libs linked with -l would require
|
||||
def get_ldpathflags(self, names, exclude = []):
|
||||
deps = self.get_modules_from_project_txt(names, ['pkg.requires.jw'], 'build',
|
||||
scope = 2, add_self=True, names_only=True)
|
||||
r = ''
|
||||
for m in deps:
|
||||
if m in exclude:
|
||||
continue
|
||||
libname = self.get_libname([m])
|
||||
if len(libname):
|
||||
r = r + ' -L' + self.proj_dir(m) + '/lib'
|
||||
print(r[1:])
|
||||
|
||||
def get_ldflags(self, names, exclude = [], add_self_ = False):
|
||||
#print(names)
|
||||
deps = self.get_modules_from_project_txt(names, ['pkg.requires.jw'], 'build',
|
||||
scope = 1, add_self=add_self_, names_only=True)
|
||||
self.debug("deps = " + ' '.join(deps))
|
||||
#print(deps)
|
||||
r = ''
|
||||
for m in reversed(deps):
|
||||
if m in exclude:
|
||||
continue
|
||||
libname = self.get_libname([m])
|
||||
if len(libname):
|
||||
#r = r + ' -L' + self.proj_dir(m) + '/lib -l' + libname
|
||||
r = r + ' -l' + libname
|
||||
if len(r):
|
||||
ldpathflags = self.get_ldpathflags(names, exclude)
|
||||
if ldpathflags:
|
||||
r = ldpathflags + ' ' + r
|
||||
return r[1::]
|
||||
return ''
|
||||
|
||||
def contains(self, small, big):
|
||||
for i in xrange(len(big)-len(small)+1):
|
||||
for j in xrange(len(small)):
|
||||
if big[i+j] != small[j]:
|
||||
break
|
||||
else:
|
||||
return i, i+len(small)
|
||||
return False
|
||||
|
||||
def read_dep_graph(self, modules, section, graph):
|
||||
for m in modules:
|
||||
if m in graph:
|
||||
continue
|
||||
deps = self.get_modules_from_project_txt([ m ], ['pkg.requires.jw'], section,
|
||||
scope = 1, add_self=False, names_only=True)
|
||||
if not deps is None:
|
||||
graph[m] = deps
|
||||
for d in deps:
|
||||
self.read_dep_graph([ d ], section, graph)
|
||||
|
||||
def flip_graph(self, graph):
|
||||
r = {}
|
||||
for m, deps in graph.items():
|
||||
for d in deps:
|
||||
if not d in r:
|
||||
r[d] = set()
|
||||
r[d].add(m)
|
||||
return r
|
||||
|
||||
def check_circular_deps(self, module, section, graph, unvisited, temp, path):
|
||||
if module in temp:
|
||||
self.debug('found circular dependency at module', module)
|
||||
return module
|
||||
if not module in unvisited:
|
||||
return None
|
||||
temp.add(module)
|
||||
if module in graph:
|
||||
for m in graph[module]:
|
||||
last = self.check_circular_deps(m, section, graph, unvisited, temp, path)
|
||||
if last is not None:
|
||||
path.insert(0, m)
|
||||
return last
|
||||
unvisited.remove(module)
|
||||
temp.remove(module)
|
||||
|
||||
# -------------------------------------------------------------------- here we go
|
||||
def run(self):
|
||||
|
||||
skip = 0
|
||||
for a in sys.argv[1::]:
|
||||
self.global_args.append(a)
|
||||
if a in [ '-p', '--prefix', '-t', '--topdir', '-O', '--os' ]:
|
||||
skip = 1
|
||||
continue
|
||||
if skip > 0:
|
||||
skip = skip -1
|
||||
continue
|
||||
if a[0] != '-':
|
||||
break
|
||||
|
||||
# -- defaults
|
||||
self.projs_root = pwd.getpwuid(os.getuid()).pw_dir + "/local/src/jw.dev/proj"
|
||||
|
||||
parser = argparse.ArgumentParser(description='Project metadata evaluation')
|
||||
parser.add_argument('-d', '--debug', action='store_true',
|
||||
default=False, help='Output debug information to stderr')
|
||||
parser.add_argument('-t', '--topdir', nargs=1, default = [], help='Project Path')
|
||||
parser.add_argument('-p', '--prefix', nargs=1, default = [ self.projs_root ], help='App Path Prefix')
|
||||
parser.add_argument('-O', '--os', nargs=1, default = [], help='Target operating system')
|
||||
parser.add_argument('cmd', default='', help=f'Command, run "{sys.argv[0]} commands" for a list of supported commands')
|
||||
parser.add_argument('arg', nargs='*', help='Command arguments')
|
||||
args = parser.parse_args(self.global_args)
|
||||
|
||||
self.opt_debug = args.debug
|
||||
if len(args.os):
|
||||
self.opt_os = args.os[0]
|
||||
|
||||
self.debug("----------------------------------------- running ", ' '.join(sys.argv))
|
||||
|
||||
self.projs_root = args.prefix[0]
|
||||
self.debug("projs_root = ", self.projs_root)
|
||||
if len(args.topdir):
|
||||
self.topdir = args.topdir[0]
|
||||
|
||||
if self.topdir:
|
||||
self.top_name = self.res_cache.run(self.read_value, [self.topdir + '/make/project.conf', 'build', 'name'])
|
||||
if not self.top_name:
|
||||
self.top_name = re.sub('-[0-9.-]*$', '', os.path.basename(os.path.realpath(self.topdir)))
|
||||
|
||||
import importlib
|
||||
cmd_name = args.cmd.replace('-', '_')
|
||||
cc_cmd_name = 'Cmd' + ''.join(x.capitalize() for x in cmd_name.lower().split("_"))
|
||||
module = importlib.import_module('jw.pkg.build.cmds.' + cc_cmd_name)
|
||||
cmd = getattr(module, cc_cmd_name)()
|
||||
cmd.app = self
|
||||
subparser = argparse.ArgumentParser(description=cmd_name)
|
||||
cmd.add_arguments(subparser)
|
||||
args = subparser.parse_args(sys.argv[(len(self.global_args) + 1)::])
|
||||
try:
|
||||
return cmd.run(args)
|
||||
except Exception as e:
|
||||
self.err('Failed to run >{}<: {}'.format(' '.join(sys.argv), e))
|
||||
raise
|
||||
sys.exit(1)
|
||||
58
src/python/jw/pkg/build/Cmd.py
Normal file
58
src/python/jw/pkg/build/Cmd.py
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import annotations
|
||||
from typing import Type, Union, TypeVar
|
||||
import inspect, abc, argparse
|
||||
from argparse import ArgumentParser
|
||||
|
||||
class Cmd(abc.ABC): # export
|
||||
|
||||
def __init__(self, name: str, help: str) -> None:
|
||||
from ..App import App
|
||||
self.name = name
|
||||
self.help = help
|
||||
self.parent = None
|
||||
self.children: list[Cmd] = []
|
||||
self.child_classes: list[Type[Cmd]] = []
|
||||
self.app: App|None = None
|
||||
|
||||
@abc.abstractmethod
|
||||
def _run(self, args):
|
||||
pass
|
||||
|
||||
def run(self, args):
|
||||
return self._run(args)
|
||||
|
||||
def add_parser(self, parsers) -> ArgumentParser:
|
||||
r = parsers.add_parser(self.name, help=self.help,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
r.set_defaults(func=self.run)
|
||||
return r
|
||||
|
||||
def add_subcommands(self, cmd: Union[str, Type[Cmd], list[Type[Cmd]]]) -> None:
|
||||
if isinstance(cmd, str):
|
||||
import sys, re
|
||||
sc = []
|
||||
for name, obj in inspect.getmembers(sys.modules[self.__class__.__module__]):
|
||||
if inspect.isclass(obj):
|
||||
if re.search(cmd, str(obj)):
|
||||
sc.append(obj)
|
||||
log.slog(log.DEBUG, f"Found subcommand {obj}")
|
||||
self.add_subcommands(sc)
|
||||
return
|
||||
if isinstance(cmd, list):
|
||||
for c in cmd:
|
||||
self.add_subcommands(c)
|
||||
return
|
||||
self.child_classes.append(cmd)
|
||||
|
||||
# To be overridden by derived class in case the command does take arguments.
|
||||
# Will be called from App base class constructor and set up the parser hierarchy
|
||||
def add_arguments(self, parser: ArgumentParser) -> None:
|
||||
pass
|
||||
|
||||
def conf_value(self, path, default=None):
|
||||
ret = None if self.app is None else self.app.conf_value(path, default)
|
||||
if ret is None and default is not None:
|
||||
return default
|
||||
return ret
|
||||
5
src/python/jw/pkg/build/Makefile
Normal file
5
src/python/jw/pkg/build/Makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
TOPDIR = ../../../../..
|
||||
PY_UPDATE_INIT_PY = false
|
||||
|
||||
include $(TOPDIR)/make/proj.mk
|
||||
include $(JWBDIR)/make/py-mod.mk
|
||||
0
src/python/jw/pkg/build/__init__.py
Normal file
0
src/python/jw/pkg/build/__init__.py
Normal file
102
src/python/jw/pkg/build/cmds/BaseCmdPkgRelations.py
Normal file
102
src/python/jw/pkg/build/cmds/BaseCmdPkgRelations.py
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
from argparse import Namespace, ArgumentParser
|
||||
|
||||
from ..Cmd import Cmd
|
||||
|
||||
class BaseCmdPkgRelations(Cmd):
|
||||
|
||||
def pkg_relations(self, rel_type, args):
|
||||
version_pattern=re.compile("[0-9-.]*")
|
||||
if args.subsections is None:
|
||||
subsecs = self.app.os_cascade()
|
||||
subsecs.append('jw')
|
||||
else:
|
||||
subsecs = args.subsections.split(',')
|
||||
self.app.debug('flavour = ', args.flavour, ', subsecs = ', ' '.join(subsecs))
|
||||
ignore = args.ignore.split(',')
|
||||
self.app.debug("ignore = ", ignore)
|
||||
|
||||
r = []
|
||||
flavours = args.flavour.split(',')
|
||||
for flavour in flavours:
|
||||
for s in subsecs:
|
||||
section = 'pkg.' + rel_type + '.' + s
|
||||
visited = set()
|
||||
modules = args.module.copy()
|
||||
while len(modules):
|
||||
m = modules.pop(0)
|
||||
if m in visited or m in ignore:
|
||||
continue
|
||||
visited.add(m)
|
||||
value = self.app.get_value(m, section, flavour)
|
||||
if not value:
|
||||
continue
|
||||
deps = value.split(',')
|
||||
for spec in deps:
|
||||
dep = re.split('([=><]+)', spec)
|
||||
if args.no_version:
|
||||
dep = dep[:1]
|
||||
dep = list(map(str.strip, dep))
|
||||
dep_name = re.sub('-dev$|-devel$|-run$', '', dep[0])
|
||||
if dep_name in ignore or dep[0] in ignore:
|
||||
continue
|
||||
if args.no_subpackages:
|
||||
dep[0] = dep_name
|
||||
for i, item in enumerate(dep):
|
||||
dep[i] = item.strip()
|
||||
if s == 'jw':
|
||||
if args.recursive and not dep_name in visited and not dep_name in modules:
|
||||
modules.append(dep_name)
|
||||
if len(dep) == 3:
|
||||
if args.dont_expand_version_macros and dep_name in args.module:
|
||||
version = dep[2]
|
||||
else:
|
||||
version = self.app.get_value(dep_name, 'version', '')
|
||||
if dep[2] == 'VERSION':
|
||||
if args.dont_strip_revision:
|
||||
dep[2] = version
|
||||
else:
|
||||
dep[2] = version.split('-')[0]
|
||||
elif dep[2] == 'VERSION-REVISION':
|
||||
dep[2] = version
|
||||
elif version_pattern.match(dep[2]):
|
||||
# dep[2] = dep[2]
|
||||
pass
|
||||
else:
|
||||
raise Exception("Unknown version specifier in " + spec)
|
||||
cleaned_dep = ' '.join(dep)
|
||||
if not cleaned_dep in r:
|
||||
self.app.debug("appending", cleaned_dep)
|
||||
r.append(cleaned_dep)
|
||||
return args.delimiter.join(r)
|
||||
|
||||
def print_pkg_relations(self, rel_type, args_):
|
||||
print(self.pkg_relations(rel_type, args_))
|
||||
|
||||
def __init__(self, relation: str, help: str) -> None:
|
||||
super().__init__('pkg-' + relation, help=help)
|
||||
self.relation = relation
|
||||
|
||||
def add_arguments(self, parser: ArgumentParser) -> None:
|
||||
super().add_arguments(parser)
|
||||
parser.add_argument('-S', '--subsections', nargs='?', default=None, help='Subsections to consider, comma-separated')
|
||||
parser.add_argument('-d', '--delimiter', nargs='?', default=', ', help='Output words delimiter')
|
||||
parser.add_argument('flavour', help='Flavour')
|
||||
parser.add_argument('module', nargs='*', help='Modules')
|
||||
parser.add_argument('-p', '--no-subpackages', action='store_true',
|
||||
default=False, help='Cut -run and -devel from package names')
|
||||
parser.add_argument('--no-version', action='store_true',
|
||||
default=False, help='Don\'t report version information')
|
||||
parser.add_argument('--dont-strip-revision', action='store_true',
|
||||
default=False, help='Always treat VERSION macro as VERSION-REVISION')
|
||||
parser.add_argument('--recursive', action='store_true',
|
||||
default=False, help='Find dependencies recursively')
|
||||
parser.add_argument('--dont-expand-version-macros', action='store_true',
|
||||
default=False, help='Don\'t expand VERSION and REVISION macros')
|
||||
parser.add_argument('--ignore', nargs='?', default='', help='Packages that '
|
||||
'should be ignored together with their dependencies')
|
||||
|
||||
def _run(self, args: Namespace) -> None:
|
||||
return self.print_pkg_relations(self.relation, args)
|
||||
174
src/python/jw/pkg/build/cmds/CmdBuild.py
Normal file
174
src/python/jw/pkg/build/cmds/CmdBuild.py
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os, re, sys, subprocess, datetime
|
||||
from argparse import Namespace, ArgumentParser
|
||||
|
||||
from ..Cmd import Cmd
|
||||
|
||||
class CmdBuild(Cmd): # export
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__('build', help='janware software project build tool')
|
||||
|
||||
def add_arguments(self, parser: ArgumentParser) -> None:
|
||||
super().add_arguments(parser)
|
||||
parser.add_argument('--exclude', default='', help='Space seperated ist of modules to be excluded from build')
|
||||
parser.add_argument('-n', '--dry-run', action='store_true',
|
||||
default=False, help='Don\'t build anything, just print what would be done.')
|
||||
parser.add_argument('-O', '--build-order', action='store_true',
|
||||
default=False, help='Don\'t build anything, just print the build order.')
|
||||
parser.add_argument('-I', '--ignore-deps', action='store_true',
|
||||
default=False, help='Don\'t build dependencies, i.e. build only modules specified on the command line')
|
||||
parser.add_argument('target', default='all', help='Build target')
|
||||
parser.add_argument('modules', nargs='+', default='', help='Modules to be built')
|
||||
|
||||
def _run(self, args: Namespace) -> None:
|
||||
|
||||
def read_deps(cur, prereq_type):
|
||||
# dep cache doesn't make a difference at all
|
||||
if prereq_type in self.app.dep_cache:
|
||||
if cur in self.app.dep_cache[prereq_type]:
|
||||
return self.app.dep_cache[prereq_type][cur]
|
||||
else:
|
||||
self.app.dep_cache[prereq_type] = {}
|
||||
|
||||
r = self.app.get_modules_from_project_txt([ cur ], ['pkg.requires.jw'],
|
||||
prereq_type, scope = 2, add_self=False, names_only=True)
|
||||
self.app.debug('prerequisites = ' + ' '.join(r))
|
||||
if cur in r:
|
||||
r.remove(cur)
|
||||
self.app.debug('inserting', prereq_type, "prerequisites of", cur, ":", ' '.join(r))
|
||||
self.app.dep_cache[prereq_type][cur] = r
|
||||
return r
|
||||
|
||||
def read_deps_cached(cur, prereq_type):
|
||||
return self.app.res_cache.run(read_deps, [ cur, prereq_type ])
|
||||
|
||||
def add_dep_tree(cur, prereq_types, tree, all_deps):
|
||||
self.app.debug("adding prerequisites " + ' '.join(prereq_types) + " of module " + cur)
|
||||
if cur in all_deps:
|
||||
self.app.debug('already handled module ' + cur)
|
||||
return 0
|
||||
deps = set()
|
||||
all_deps.add(cur)
|
||||
for t in prereq_types:
|
||||
self.app.debug("checking prereqisites of type " + t)
|
||||
deps.update(read_deps_cached(cur, t))
|
||||
for d in deps:
|
||||
add_dep_tree(d, prereq_types, tree, all_deps)
|
||||
tree[cur] = deps
|
||||
return len(deps)
|
||||
|
||||
def calculate_order(order, modules, prereq_types):
|
||||
all_deps = set()
|
||||
dep_tree = {}
|
||||
for m in modules:
|
||||
self.app.debug("--- adding dependency tree of module " + m)
|
||||
add_dep_tree(m, prereq_types, dep_tree, all_deps)
|
||||
while len(all_deps):
|
||||
# Find any leaf
|
||||
for d in all_deps:
|
||||
if not len(dep_tree[d]): # Dependency d doesn't have dependencies itself
|
||||
break # found
|
||||
else: # no Leaf found
|
||||
print(all_deps)
|
||||
raise Exception("fatal: the dependencies between these modules are unresolvable")
|
||||
order.append(d) # do it
|
||||
# bookkeep it
|
||||
all_deps.remove(d)
|
||||
for k in dep_tree.keys():
|
||||
if d in dep_tree[k]:
|
||||
dep_tree[k].remove(d)
|
||||
return 1
|
||||
|
||||
def run_make(module, target, cur_project, num_projects):
|
||||
#make_cmd = "make " + target + " 2>&1"
|
||||
make_cmd = [ "make", target ]
|
||||
path = self.app.proj_dir(module)
|
||||
delim_len = 120
|
||||
delim = '---- [%d/%d]: running %s in %s -' % (cur_project, num_projects, make_cmd, path)
|
||||
delim = delim + '-' * (delim_len - len(delim))
|
||||
|
||||
print(',' + delim + ' >')
|
||||
|
||||
patt = self.app.is_excluded_from_build(module)
|
||||
if patt is not None:
|
||||
print('| Configured to skip build on platform >' + patt + '<')
|
||||
print('`' + delim + ' <')
|
||||
return
|
||||
|
||||
os.chdir(path)
|
||||
p = subprocess.Popen(make_cmd, shell=False, stdout=subprocess.PIPE, stderr=None, close_fds=True)
|
||||
for line in iter(p.stdout.readline, b''):
|
||||
line = line.decode(sys.stdout.encoding)
|
||||
sys.stdout.write('| ' + line) # avoid extra newlines from print()
|
||||
sys.stdout.flush()
|
||||
p.wait()
|
||||
print('`' + delim + ' <')
|
||||
if p.returncode:
|
||||
print(' '.join(make_cmd) + ' failed')
|
||||
raise Exception(time.strftime("%Y-%m-%d %H:%M") + ": failed to make target " + target + " in module " + module + " below base " + self.app.projs_root)
|
||||
|
||||
def run_make_on_modules(modules, order, target):
|
||||
cur_project = 0
|
||||
num_projects = len(order)
|
||||
if target in ["clean", "distclean"]:
|
||||
for m in reversed(order):
|
||||
cur_project += 1
|
||||
run_make(m, target, cur_project, num_projects)
|
||||
if m in modules:
|
||||
modules.remove(m)
|
||||
if not len(modules):
|
||||
print("all modules cleaned")
|
||||
return
|
||||
else:
|
||||
for m in order:
|
||||
cur_project += 1
|
||||
run_make(m, target, cur_project, num_projects)
|
||||
|
||||
def run(args):
|
||||
|
||||
self.app.debug("----------------------------------------- running ", ' '.join(sys.argv))
|
||||
|
||||
modules = args.modules
|
||||
exclude = args.exclude.split()
|
||||
target = args.target
|
||||
|
||||
env_exclude = os.getenv('BUILD_EXCLUDE', '')
|
||||
if len(env_exclude):
|
||||
print("exluding modules from environment: " + env_exclude)
|
||||
exclude += " " + env_exclude
|
||||
|
||||
# -- build
|
||||
order = []
|
||||
|
||||
glob_prereq_types = [ "build" ]
|
||||
if re.match("pkg-.*", target) is not None:
|
||||
glob_prereq_types = [ "build", "run", "release", "devel" ]
|
||||
|
||||
if target != 'order' and not args.build_order:
|
||||
print("using prerequisite types " + ' '.join(glob_prereq_types))
|
||||
print("calculating order for modules ... ")
|
||||
|
||||
calculate_order(order, modules, glob_prereq_types)
|
||||
if args.ignore_deps:
|
||||
order = [m for m in order if m in args.modules]
|
||||
order = [m for m in order if m not in exclude]
|
||||
if target == 'order' or args.build_order:
|
||||
print(' '.join(order))
|
||||
exit(0)
|
||||
|
||||
cur_project = 0
|
||||
print("Building target %s in %d projects:" % (target, len(order)))
|
||||
for m in order:
|
||||
cur_project += 1
|
||||
print(" %3d %s" % (cur_project, m))
|
||||
|
||||
if args.dry_run:
|
||||
exit(0)
|
||||
|
||||
run_make_on_modules(modules, order, target)
|
||||
|
||||
print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
||||
|
||||
run(args)
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue