Compare commits

..

12 Commits

Author SHA1 Message Date
Arjan van de Ven 0fd1fc5a1d packages update 2024-07-30 16:29:55 +00:00
William Douglas 0e9a2b7e82 Force git attributes for vendor directories
Avoid cases where user git settings cause files to have different line
endings than the package and cause hash mismatches when building.

Signed-off-by: William Douglas <william.douglas@intel.com>
2024-07-25 12:45:07 -07:00
William Douglas 398fb69708 Always remove the pumpAutospec file
Remove pumpAutospec even if the package hasn't yet become a git repo
yet.

Signed-off-by: William Douglas <william.douglas@intel.com>
2024-07-24 15:36:47 -07:00
William Douglas cdcb8aa9d8 Switch to git rm for removing the autospec log file
Signed-off-by: William Douglas <william.douglas@intel.com>
2024-07-22 16:38:33 -07:00
Arjan van de Ven 3168ba058e update 2024-07-22 23:22:51 +00:00
William Douglas 76fef57d5b Add env var for autospec logging
Add environment variable that autospec uses to decide when to log
fatal errors to a special file used for the update process.

Also does the cleanup of the autospec created file for new autospec
runs.

Signed-off-by: William Douglas <william.douglas@intel.com>
2024-07-22 16:20:55 -07:00
Arjan van de Ven 59ea0b102e new packages file 2024-07-09 18:23:06 +00:00
William Douglas e4c604a161 Export the output of cargo vendor
autospec learned how to use 'cargo vendor' output as a drop in
configuration file so put the output of cargo vendor there.

Signed-off-by: William Douglas <william.douglas@intel.com>
2024-07-08 15:11:34 -07:00
William Douglas 59c4520f37 Fix import order
Signed-off-by: William Douglas <william.douglas@intel.com>
2024-07-08 14:07:10 -07:00
William Douglas 16f813a390 Add support for update.first
Add additional capability for update target to read a package's
update.first file that will run make update on each of the packages
included in that file.

The intended usage model is for packages that need to be updated in
order to specify that order via the update.first (the packages are
updated in the order specified unless a package in the list also has
an update.first file).

As part of this change, force the update target to always build in
koji synchronously to avoid issues where the update being depended on
isn't finished in koji.

Loops are not supported and will cause problems.

Signed-off-by: William Douglas <william.douglas@intel.com>
2024-07-03 15:03:11 -07:00
William Douglas 79eebc6aa6 Remove autospecnewgo target and its component parts
This wasn't a practical target and is no longer used so remove it.

Signed-off-by: William Douglas <william.douglas@intel.com>
2024-07-03 13:33:17 -07:00
William Douglas d1accc8077 Fix CLEANUP option handling for autospecnew target
Signed-off-by: William Douglas <william.douglas@intel.com>
2024-07-03 11:34:09 -07:00
5 changed files with 46 additions and 363 deletions
+9 -20
View File
@@ -166,6 +166,7 @@ preautospec-checks:
#help to autospec.
#help For more information, see the project at https://github.com/clearlinux/autospec
autospec: preautospec-checks pullrebase localreponotice clean-old-content
git rm --ignore-unmatch pumpAutospec || rm -f pumpAutospec
@if [ -e $(SPECFILE) ] && ! grep -q "# Generated by: autospec.py" $(SPECFILE) ; then \
echo "Specfile already exists and was not created by autospec.py! Aborting."; \
exit 1; \
@@ -406,17 +407,20 @@ update-versions:
#help or update the package and push the update to koji.
#help If no update.sh exists, update the version, autospec and push the
#help update to koji (bumping the bump.list if found).
update: export AUTOSPEC_UPDATE=1
update:
@if [ -f update.first ]; then \
for pkg in $$(< update.first); do \
(cd "../$${pkg}" || exit 1; $(MAKE) update-versions || exit 0; $(MAKE) update) || exit; \
done; \
fi
@if [ -f update.sh ]; then \
./update.sh; \
else \
$(MAKE) -s update-versions && \
$(MAKE) autospec CLEANUP=1 && \
if [ -f bump.list ]; then \
$(MAKE) -s koji; \
else \
$(MAKE) -s koji-nowait; \
fi \
$(MAKE) -s koji && \
$(MAKE) koji-waitrepo; \
fi \
logcheck:
@@ -440,21 +444,6 @@ repoadd: $(TOPLVL)/repo
$(MAKE) -s localrepocreate
$(MAKE) -s localrepoenable
#help repostage: Stages locally-built RPMs for this package to the local RPM
#help directory. If this directory does not yet exist, it is created and
#help enabled.
repostage: $(TOPLVL)/repo
@if [ -z "${LATEST_RPMS}" ]; then \
echo "No rpms found in rpms/ directory."; \
exit 1; \
fi
$(MAKE) -s repodel NO_CREATEREPO=1
@for r in ${LATEST_RPMS}; do \
echo "+$${rpm#rpms/}"; \
echo "$${rpm#rpms/}" >> .repo-index; \
done; \
flock $</repo.lock ln -f -t $< ${LATEST_RPMS}
#help repodel: Removes RPMs from the local RPM repository that were
#help previously added by 'make repoadd' for this package.
repodel: $(TOPLVL)/repo
+1 -46
View File
@@ -237,7 +237,7 @@ autospecnew: preautospecnew-checks localreponotice
--mock-config $(MOCK_CONFIG_VAL) \
--mock-opts="$(MOCK_OPTS)" \
$${SETVERSION:+ --version $${SETVERSION}} \
${NON_INTERACTIVE} ${SKIP_GIT} ${CLEANUP} \
${NON_INTERACTIVE} ${SKIP_GIT} $(if $(CLEANUP),-C) \
$(URL); \
if [ $$? -eq 0 ]; then \
$(MAKE) link-new-rpms PKG_REPO_DIR="${TOPLVL}/packages/${NAME}"; \
@@ -256,51 +256,6 @@ autospecnew: preautospecnew-checks localreponotice
exit 1; \
fi
#help autospecnewgo: Creates a new autospec package with (dependencies)
#help for a given URL=$(URL) with NAME=$(NAME). Several files used by
#help autospec will be created in the help process.
#help Use MOCK_OPTS environment varible to pass down arbitrary mock options
#help to autospec.
#help For more information about autospec, see the project page on Github https://github.com/clearlinux/autospec
autospecnewgo: preautospecnew-checks localreponotice
@if [ -z $(NAME) ] || [ -z $(URL) ]; then \
echo "Please specify NAME and URL. The ARCHIVES variable is optional."; \
exit 1; \
fi
-$(MAKE) clone_$(NAME)
@if [ ! -d $(TOPLVL)/packages/$(NAME)/.git ]; then \
echo "no remote repository found, creating new package repository and running autospec"; \
mkdir -p $(TOPLVL)/packages/$(NAME); \
( \
cd $(TOPLVL)/packages/$(NAME); \
git init -b main; \
git remote add origin $(PKG_BASE_URL)/$(NAME); \
$(call gitoliteurl,packages/$(NAME)); \
$(call subjectprefix,$(NAME)); \
); \
printf 'PKG_NAME := %s\nURL = %s\nARCHIVES = %s\n\ninclude ../common/Makefile.common\n' $(NAME) '$(value URL)' '$(value ARCHIVES)' > $(TOPLVL)/packages/$(NAME)/Makefile; \
python3 $(TOPLVL)/projects/common/go-builder.py \
--target packages/$(NAME) \
--integrity \
--config "$(AUTOSPEC_CONF)" \
--name $(NAME) \
--archives $(ARCHIVES) \
--mock-config $(MOCK_CONFIG_VAL) \
--mock-opts "$(MOCK_OPTS)" \
$(URL); \
if [ $$? -eq 0 ]; then \
$(MAKE) link-new-rpms PKG_REPO_DIR="${TOPLVL}/packages/${NAME}"; \
$(TOPLVL)/projects/common/checkblacklist.sh $(TOPLVL)/projects/common/blacklist $(TOPLVL)/packages/${NAME}/results/*.rpm; \
python3 $(TOPLVL)/projects/common/patchfilter.py <(git -C $(TOPLVL)/packages/$(NAME) show) > $(TOPLVL)/packages/$(NAME)/for-review.txt; \
python3 $(TOPLVL)/projects/common/patchfilter.py <(git -C $(TOPLVL)/packages/$(NAME) show); \
else \
exit 1; \
fi; \
else \
echo "$(NAME) already exists at $(TOPLVL)/packages/$(NAME)"; \
exit 1; \
fi
#help repoenable: Enables the local RPM repository for use with Yum/DNF and
#help Mock. If this repository does not yet exist, it is created.
repoenable: localrepoenable ;
-285
View File
@@ -1,285 +0,0 @@
#!/usr/bin/env python3
#
# gowrap.py - part of autospec
# Copyright (C) 2019 Intel Corporation
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
import argparse
import os
import shutil
import subprocess
import sys
import tempfile
def parse_args():
"""Parse commandline arguments."""
parser = argparse.ArgumentParser()
parser.add_argument("url", help="Location of package archive")
parser.add_argument("-t", "--target", dest="target", action="store",
default=None,
help="Target location to create or reuse")
parser.add_argument("-c", "--config", dest="config", action="store",
default="/usr/share/defaults/autospec/autospec.conf",
help="Set configuration file to use")
parser.add_argument("-n", "--name", action="store", dest="name", default="",
help="Override the package name")
parser.add_argument("-i", "--integrity", action="store_true",
default=False,
help="Search for package signature from source URL and "
"attempt to verify package")
parser.add_argument("-m", "--mock-config", action="store", default="clear",
help="Value to pass with Mock's -r option. Defaults to "
"\"clear\", meaning that Mock will use "
"/etc/mock/clear.cfg.")
parser.add_argument("-o", "--mock-opts", action="store", default="",
help="Arbitrary options to pass down to mock when "
"building a package.")
parser.add_argument('-a', "--archives", action="store",
dest="archives", default=[], nargs='*',
help="tarball URLs for additional source archives and"
" a location for the sources to be extacted to (e.g."
" http://example.com/downloads/dependency.tar.gz"
" /directory/relative/to/extract/root )")
return parser.parse_args()
def missing_dependencies(name):
"""Check if the build failed due to missing dependencies."""
root_log = os.path.join("packages", name, "results", "root.log")
if not os.path.exists(root_log):
return False
with open(root_log, "r") as lfile:
for line in lfile.readlines():
if "No matching package to install" in line:
return True
return False
def already_built(name, version):
"""Check if the package and version are already built."""
if not os.path.exists(os.path.join("packages", name, "rpms")):
return False
vpath = os.path.join("packages", name, "versions")
if not os.path.exists(vpath):
return False
with open(vpath, "r") as vfile:
if version not in [x.strip() for x in vfile.readlines()]:
return False
return True
def build(path, args, name, url, version):
"""Try and build a package."""
if version:
ver_arg = ["-v", version]
else:
ver_arg = []
if already_built(name, version):
return True
print(f"Trying to autospec {name} - {version}")
proc = subprocess.run(["python3",
f"{path}/../autospec/autospec/autospec.py", url,
"-c", args.config, "-t", f"packages/{name}",
"-n", name, "-m", args.mock_config,
"-o", args.mock_opts, "-i"] + ver_arg, capture_output=True)
if proc.returncode == 0:
subprocess.run(["make", "link-new-rpms", f"PKG_REPO_DIR=packages/{name}"],
capture_output=True)
return proc.returncode == 0
def parse_go_mod(path):
"""Parse go.mod file for build requirements.
File content looks as follows:
module example.com/foo/bar
require (
github.com/BurntSushi/toml v0.3.1
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999
github.com/inconshreveable/mousetrap v1.0.0 // indirect
"github.com/spf13/cobra" v0.0.3
github.com/spf13/pflag v1.0.3 // indirect
)
Need to handle all require lines including //indirect.
Skip requires that use .git for now. May need to be handled
differently.
"""
reqs = []
with open(path, "r") as gfile:
dep_start = False
for line in gfile.readlines():
# Ideally the mod file is generated and the format is
# always correct but add a few defenses just in case
line = line.strip()
if line.startswith("//"):
# Skip comments
continue
if dep_start:
# End of the require section
if line.startswith(")"):
break
req = line.split()[:2]
req[0] = req[0].replace('"', '')
if req[0].endswith(".git"):
continue
reqs.append(req)
continue
if line.startswith("require ("):
dep_start = True
return reqs
def get_dependencies(name):
"""Return path to the go.mod file if it exists."""
command = None
path = None
pdir = os.path.join("packages", name)
reqs = []
for fname in os.listdir(pdir):
# Find the archive
if fname.endswith("zip"):
command = ["unzip", fname]
elif ".tar." in fname:
command = ["tar", "xf", fname]
else:
command = None
if command:
# Decompress archive
tdir = tempfile.mkdtemp()
tfile = os.path.join(tdir, fname)
shutil.copyfile(os.path.join(pdir, fname), tfile)
proc = subprocess.run(command, cwd=tdir, capture_output=True)
if not proc.returncode:
# inspect contents for a "go.sum" file
for root, _, files in os.walk(tdir):
if "go.mod" in files:
path = f"{name}.gomod"
shutil.copyfile(os.path.join(root, "go.mod"), path)
reqs += parse_go_mod(path)
os.unlink(path)
shutil.rmtree(tdir)
return reqs
def encode_requirements(requirement):
"""Encode the project's module and version."""
# Default dependency base proxy url
base_url = "https://proxy.golang.org/"
# Encoding based on
# https://tip.golang.org/cmd/go/#hdr-Module_proxy_protocol
encoded_module = ""
for char in requirement[0]:
if char.isupper():
encoded_module += "!" + char.lower()
else:
encoded_module += char
encoded_version = ""
for char in requirement[1]:
if char.isupper():
encoded_version += "!" + char.lower()
else:
encoded_version += char
return (encoded_module, encoded_version)
def initialize_package(name, url, version, path, args):
"""Setup package and try to build it."""
if already_built(name, version):
return True
print(f"Trying to autospecnew {name} - {version}")
proc = subprocess.run(["make", "autospecnew", f"URL={url}", f"NAME={name}", f"SETVERSION={version}"], capture_output=True)
if f"{name} already exists at" in proc.stdout.decode("utf-8"):
return build(path, args, name, url, version)
return proc.returncode == 0
def build_recursive(path, args, name, url, version=None, success=None):
"""Try and recursively build packages."""
if not success:
# First package being built, common utilities already run
# so just use autospec directly
success = {}
ret = build(path, args, name, url, version)
else:
ret = initialize_package(name, url, version, path, args)
if ret:
# Completed so we are done!
return True
if not missing_dependencies(name):
# Failed but not due to missing dependencies, bail
print(f"Unknown error building {name} - {version}")
return False
reqs = get_dependencies(name)
if not reqs:
# Didn't try and add anything so don't need to build again
print(f"Build failed with no missing requirements: {name} - {version}")
return False
print(f"First attempt to build failed due to missing dependencies {name} - {version}\n")
for req in reqs:
ereq = encode_requirements(req)
rname = "go-" + req[0].replace("/", "-")
rurl = f"https://proxy.golang.org/{ereq[0]}/@v/list"
if (rname, req[1]) in success:
# Rebuild detected, figure out if it is okay or not
if success[(rname, req[1])]:
# Already succeeded building req short circuit success
continue
else:
# Encountered a build loop, bail out as this likely
# requires manual fixing
print(f"Detected build loop when building {rname} - {req[1]}")
return True
success[(rname, req[1])] = False
if not build_recursive(path, args, rname, rurl, req[1], success):
print(f"Failed to build dependency {rname} - {req[1]}")
return False
success[(rname, req[1])] = True
subprocess.run(["make", "repodel"], cwd=f"packages/{rname}", capture_output=True)
subprocess.run(["make", "repostage"], cwd=f"packages/{rname}", capture_output=True)
# Create the repo with the new packages added
subprocess.run(["make", "localrepocreate"], capture_output=True)
# Retry previously failed build assuming dependencies got added
print(f"Rebuilding after resolving dependencies {name} - {version}")
ret = build(path, args, name, url, version)
print("")
return ret
def main():
"""Start program execution."""
args = parse_args()
path = os.path.dirname(os.path.realpath(__file__))
return build_recursive(path, args, args.name, args.url)
if __name__ == '__main__':
if not main():
sys.exit(-1)
print("\n\nBuild completed\n\n")
+23 -3
View File
@@ -121,6 +121,7 @@ R-MNP
R-MatchIt
R-Matching
R-MatrixModels
R-MetricsWeighted
R-ModelMetrics
R-NADA
R-NLP
@@ -148,6 +149,7 @@ R-RNetCDF
R-ROCR
R-ROSE
R-RProtoBuf
R-RPushbullet
R-RSQLite
R-RSclient
R-RUnit
@@ -216,6 +218,7 @@ R-arules
R-ash
R-askpass
R-assertthat
R-audio
R-backports
R-base64enc
R-base64url
@@ -338,6 +341,7 @@ R-distr
R-distrEx
R-distributional
R-dlm
R-doBy
R-doMC
R-doMPI
R-doParallel
@@ -351,6 +355,7 @@ R-drc
R-dreamerr
R-dtplyr
R-dtw
R-duckdb
R-dygraphs
R-dynamicTreeCut
R-dynlm
@@ -656,6 +661,7 @@ R-mvnormtest
R-mvoutlier
R-mvtnorm
R-nanoarrow
R-nanoparquet
R-natserv
R-ncbit
R-ncdf4
@@ -914,6 +920,7 @@ R-spatstat.linnet
R-spatstat.model
R-spatstat.random
R-spatstat.sparse
R-spatstat.univar
R-spatstat.utils
R-spc
R-spdep
@@ -963,6 +970,7 @@ R-tibble
R-tidyr
R-tidyrules
R-tidyselect
R-tidytable
R-tidyverse
R-tikzDevice
R-timeDate
@@ -1072,6 +1080,7 @@ WPEBackend-fdo
WireGuard
XStatic-term.js
Z3
aardvark-dns
abireport
abseil-cpp
accel-config
@@ -1160,7 +1169,6 @@ bash-completion
bashdb
bats
bc
bcache-tools
bcachefs-tools
bcc
bcftools
@@ -1221,6 +1229,7 @@ byobu
bz2file
bzip2
c-ares
c-blosc2
cJSON
c_rehash
ca-certs
@@ -1246,6 +1255,7 @@ cereal
cfitsio
cgdb
cgit
chafa
check
cheese
chirp
@@ -1299,7 +1309,6 @@ cmocka
cmrt
cmus
cnf
cni
cni-plugins
cockpit
codec2
@@ -1392,6 +1401,7 @@ dbus-glib
dbus-python
dconf
dconf-editor
ddcutil
ddd
deap
debugedit
@@ -1500,8 +1510,10 @@ fakeroot
falcosecurity-libs
fann
farstream
fastfetch
faultstat
fcgi
fd
fdk-aac
fdupes
feh
@@ -2347,6 +2359,7 @@ libva-intel-driver
libva-utils
libvdpau
libvirt
libvirt-dbus
libvirt-glib
libvirt-python
libvisio
@@ -2503,6 +2516,7 @@ modsecurity
modsecurity-nginx
modules
mokutil
mold
mono
moreutils
mosh
@@ -2552,6 +2566,7 @@ neovim
net-snmp
net-tools
netaddr
netavark
netbase
netcdf
netcdf-fortran
@@ -2678,6 +2693,7 @@ parallel
parley
parted
pass
passt
passwdqc
patch
patchelf
@@ -3859,6 +3875,7 @@ pypi-cu2qu
pypi-curio
pypi-cvss
pypi-cxxfilt
pypi-cysystemd
pypi-cython
pypi-cytoolz
pypi-dacite
@@ -3941,6 +3958,7 @@ pypi-flaky
pypi-flask
pypi-flatbuffers
pypi-flatten_json
pypi-flexcache
pypi-flexparser
pypi-flit
pypi-flit_core
@@ -4208,6 +4226,7 @@ pypi-numexpr
pypi-numpoly
pypi-numpy
pypi-numpydoc
pypi-nvidia_ml_py
pypi-oauth2client
pypi-oauthlib
pypi-olefile
@@ -4217,6 +4236,7 @@ pypi-openshift
pypi-openstep_plist
pypi-opt_einsum
pypi-ordered_set
pypi-orjson
pypi-ouimeaux
pypi-outcome
pypi-overrides
@@ -4361,7 +4381,6 @@ pypi-pypresence
pypi-pyproject_api
pypi-pyproject_hooks
pypi-pyproject_metadata
pypi-pyprojectx
pypi-pypsrp
pypi-pyqrcode
pypi-pyqt5_sip
@@ -4955,6 +4974,7 @@ slurm
smartmontools
smemstat
snappy
snapshot
sndio
socat
socket.io-client-cpp
+13 -9
View File
@@ -9,9 +9,8 @@ import subprocess
import tempfile
import time
from git import Repo
import requests
from git import Repo
def vendor_check():
@@ -74,13 +73,16 @@ def update_cargo_vendor(path, name, git):
subprocess.run(f"cp -a {vendor_git} {backup_vendor_git}", cwd=path,
shell=True, check=True, stdout=subprocess.DEVNULL)
shutil.rmtree(vendor_path)
subprocess.run('cargo vendor', cwd=path, shell=True, check=True,
stdout=subprocess.DEVNULL)
cargo_vendors = subprocess.run('cargo vendor', cwd=path, shell=True,
check=True, stdout=subprocess.PIPE,
universal_newlines=True).stdout
with open(os.path.join(vendor_path, ".gitattributes"), "w", encoding='utf8') as gafile:
gafile.write("* text=false\n")
subprocess.run(f"cp -a {backup_vendor_git} {vendor_git}", cwd=path,
shell=True, check=True, stdout=subprocess.DEVNULL)
repo = Repo(vendor_path)
if not (len(repo.untracked_files) > 0 or repo.is_dirty()):
return False
return False, ""
subprocess.run('git add .', cwd=vendor_path, shell=True, check=True,
stdout=subprocess.DEVNULL)
subprocess.run('git commit -m "vendor update"', cwd=vendor_path,
@@ -92,10 +94,10 @@ def update_cargo_vendor(path, name, git):
subprocess.run(f"git push origin main:main {tag}", cwd=vendor_path,
shell=True, check=True, stdout=subprocess.DEVNULL)
time.sleep(30)
return tag
return tag, cargo_vendors
def update_cargo_sources(name, tag):
def update_cargo_sources(name, tag, cargo_vendors):
makefile = []
options = []
archive_match = os.path.join(r'\$\(CGIT_BASE_URL\)', 'vendor', name,
@@ -132,6 +134,8 @@ def update_cargo_sources(name, tag):
options.append(line)
with open('options.conf', 'w', encoding='utf8') as ofile:
ofile.writelines(options)
with open('cargo_vendors', 'w', encoding='utf8') as cfile:
cfile.write(cargo_vendors)
def main():
@@ -147,9 +151,9 @@ def main():
if vtype == 'cargo':
vdir = setup_cargo_vendor(tdir)
if vdir:
tag = update_cargo_vendor(vdir, args.name, args.git)
tag, cargo_vendors = update_cargo_vendor(vdir, args.name, args.git)
if tag:
update_cargo_sources(args.name, tag)
update_cargo_sources(args.name, tag, cargo_vendors)
updated = True
if not updated:
print(args.archives)