diff --git a/.gitignore b/.gitignore index 9935ed0..6aebed1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ SOURCES/go-rpm-macros-3.0.9.tar.gz +SOURCES/golist-0.10.1.tar.gz diff --git a/.go-rpm-macros.metadata b/.go-rpm-macros.metadata index 70f9341..93786de 100644 --- a/.go-rpm-macros.metadata +++ b/.go-rpm-macros.metadata @@ -1 +1,2 @@ 013899032cc1bcad52bb1fd4effe383e2afb7105 SOURCES/go-rpm-macros-3.0.9.tar.gz +bf428b2ba15f68df39e3da7647ccfdeb8beedd3b SOURCES/golist-0.10.1.tar.gz diff --git a/SOURCES/golist-bootstrap-cli-no-vendor.patch b/SOURCES/golist-bootstrap-cli-no-vendor.patch new file mode 100644 index 0000000..e8bc793 --- /dev/null +++ b/SOURCES/golist-bootstrap-cli-no-vendor.patch @@ -0,0 +1,322 @@ +diff --git a/cmd/golist/golist.go b/cmd/golist/golist.go +index ee028ae..e9c038d 100644 +--- a/cmd/golist/golist.go ++++ b/cmd/golist/golist.go +@@ -11,9 +11,8 @@ import ( + "strings" + "text/template" + +- "github.com/urfave/cli" +- + "pagure.io/golist/pkg/util" ++ "pagure.io/golist/pkg/cli" + ) + + var ( +@@ -100,7 +99,6 @@ func main() { + } + + app.Action = func(c *cli.Context) error { +- + if len(c.StringSlice("package-path")) == 0 { + return fmt.Errorf("--package-path is not set") + } +diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go +new file mode 100644 +index 0000000..ec91056 +--- /dev/null ++++ b/pkg/cli/cli.go +@@ -0,0 +1,293 @@ ++package cli ++ ++/* golist uses a very small portion of functionality ++ from github.com/urfave/cli. This module provides ++ minimal substitute API implementations for only the ++ core functionality used by golist, for the purpose of ++ bootstrapping golist without additional dependencies. ++*/ ++ ++import ( ++ "strings" ++ "fmt" ++ "os" ++) ++ ++type String string ++type StringSlice []string ++type Bool bool ++ ++type Flag interface { ++ name() string ++ usage() string ++} ++ ++type BoolFlag struct { ++ Name string ++ Usage string ++ Value bool ++} ++ ++type StringFlag struct { ++ Name string ++ Usage string ++ Value string ++} ++ ++type StringSliceFlag struct { ++ Name string ++ Usage string ++ Value *StringSlice ++} ++ ++type App struct { ++ Name string ++ Usage string ++ Version string ++ Flags []Flag ++ Action func(*Context) error ++ ++} ++ ++func NewApp() App { ++ var a App ++ return a ++} ++ ++func (a *App) Run(osArgs []string) error { ++ c, err := newContext(a.Flags, osArgs) ++ if err != nil { ++ return err ++ } ++ if c.Bool("help") { ++ a.PrintHelp() ++ os.Exit(0) ++ } ++ return a.Action(c) ++} ++ ++func (a *App) PrintHelp() { ++ maxNameLen := 0 ++ for _, flag := range a.Flags { ++ length := len(flag.name()) ++ if length > maxNameLen { ++ maxNameLen = length ++ } ++ } ++ fmtSpec := "%-" + fmt.Sprintf("%v", maxNameLen + 6) + "s\t%s\n" ++ fmt.Printf("%s - %s\n", a.Name, a.Usage) ++ fmt.Printf("Options:\n") ++ for _, flag := range a.Flags { ++ flagNameSlice := append([]string{canonicalName(flag)}, alternateNames(flag)...) ++ for i, _ := range flagNameSlice { ++ if len(flagNameSlice[i]) > 1 { ++ flagNameSlice[i] = fmt.Sprintf("--%s", flagNameSlice[i]) ++ } else { ++ flagNameSlice[i] = fmt.Sprintf("-%s", flagNameSlice[i]) ++ } ++ } ++ flagNameStr := strings.Join(flagNameSlice, ", ") ++ switch flag.(type) { ++ case StringFlag: ++ flagNameStr = fmt.Sprintf(" %s value", flagNameStr) ++ case StringSliceFlag: ++ flagNameStr = fmt.Sprintf(" %s value", flagNameStr) ++ case BoolFlag: ++ flagNameStr = fmt.Sprintf(" %s", flagNameStr) ++ } ++ fmt.Printf(fmtSpec, flagNameStr, flag.usage()) ++ } ++} ++ ++ ++type Context struct { ++ flagValues map[string]interface{} ++ flagDecls map[string]Flag ++ altFlags map[string]string ++ positionalArgs []string ++} ++ ++func (c *Context) Bool(flag string) bool { ++ iface, ok := c.flagDecls[flag] ++ if !ok { ++ panic("undefined flag" + flag) ++ } ++ switch iface.(type) { ++ case BoolFlag: ++ break ++ default: ++ panic("flag type mismatch - expected BoolFlag, got: " + flag) ++ } ++ val, ok := c.flagValues[flag] ++ if !ok { ++ return iface.(BoolFlag).Value ++ } ++ return val.(bool) ++} ++ ++func (c *Context) String(flag string) string { ++ iface, ok := c.flagDecls[flag] ++ if !ok { ++ panic("undefined flag" + flag) ++ } ++ switch iface.(type) { ++ case StringFlag: ++ break ++ default: ++ panic("flag type mismatch - expected StringFlag, got: " + flag) ++ } ++ val, ok:= c.flagValues[flag] ++ if !ok { ++ return iface.(StringFlag).Value ++ } ++ return val.(string) ++} ++ ++func (c *Context) StringSlice(flag string) []string { ++ iface, ok := c.flagDecls[flag]; ++ if !ok { ++ panic("undefined flag" + flag) ++ } ++ switch iface.(type) { ++ case StringSliceFlag: ++ break ++ default: ++ panic("flag type mismatch - expected StringSliceFlag, got: " + flag) ++ } ++ val, ok := c.flagValues[flag] ++ if !ok { ++ val = iface.(StringSliceFlag).Value ++ if val != nil { ++ return []string{} ++ } ++ } ++ return val.([]string) ++} ++ ++// Create a hash mapping from flag names to declarations ++// and alt names to flag names. ++func (c *Context) setupFlags(flagDecls []Flag) error { ++ helpFlag := BoolFlag { ++ Name: "help, h", ++ Usage: "Show help message", ++ } ++ flagDecls = append(flagDecls, helpFlag) ++ for _, flag := range flagDecls { ++ flagName := canonicalName(flag) ++ if _, ok:= c.flagDecls[flagName]; ok { ++ return fmt.Errorf("cannot redeclare flag: %s", flagName) ++ } ++ c.flagDecls[flagName] = flag ++ altFlagNames := alternateNames(flag) ++ for _, altName := range altFlagNames { ++ c.altFlags[altName] = flagName ++ } ++ } ++ return nil ++} ++ ++func (c *Context) parseArgs(osArgs []string) error { ++ // process command line arguments as a stream of tokens. ++ // operations consume the first token in the stream until ++ // the stream is empty. ++ argStream := osArgs ++ for len(argStream) > 0 { ++ arg := argStream[0] ++ if ! isFlag(arg) { ++ argStream = argStream[1:] ++ c.positionalArgs = append(c.positionalArgs, arg) ++ ++ } else { ++ arg = trimFlag(arg) ++ if _, ok:= c.altFlags[arg]; ok { ++ arg = c.altFlags[arg] ++ } ++ iface, ok := c.flagDecls[arg] ++ if !ok { ++ return fmt.Errorf("unexpected argument: %v", arg) ++ } ++ switch flag := iface.(type) { ++ case StringFlag: ++ argStream = argStream[1:] ++ if len(argStream) == 0 { ++ return fmt.Errorf("expected value for argument: %v", arg) ++ } ++ if isFlag(argStream[0]) { ++ return fmt.Errorf("unexpected flag: %v", arg) ++ } ++ c.flagValues[arg] = argStream[0] ++ case StringSliceFlag: ++ argStream = argStream[1:] ++ if len (argStream) == 0 { ++ return fmt.Errorf("expected value for argument: %v", arg) ++ } ++ if isFlag(argStream[0]) { ++ return fmt.Errorf("unexpected flag: %v", arg) ++ } ++ c.flagValues[arg] = make([]string, 0) ++ c.flagValues[arg] = append(c.flagValues[arg].([]string), argStream[0]) ++ argStream = argStream[1:] ++ for len(argStream) > 0 && ! isFlag(argStream[0]) { ++ c.flagValues[arg] = append(c.flagValues[arg].([]string), argStream[0]) ++ argStream = argStream[1:] ++ } ++ case BoolFlag: ++ argStream = argStream[1:] ++ c.flagValues[canonicalName(flag)] = true ++ default: ++ return fmt.Errorf("unexpected flag: %v", arg) ++ } ++ } ++ } ++ return nil ++} ++ ++func newContext(flags []Flag, osArgs []string) (*Context, error) { ++ var c Context ++ c.flagValues = make(map[string]interface{}) ++ c.flagDecls = make(map[string]Flag) ++ c.altFlags = make(map[string]string) ++ c.altFlags = make(map[string]string) ++ if err := c.setupFlags(flags); err != nil { ++ return nil, err ++ } ++ if err := c.parseArgs(osArgs); err != nil { ++ return nil, err ++ } ++ return &c, nil ++} ++ ++func (f StringFlag) name() string {return f.Name} ++func (f StringFlag) usage() string {return f.Usage} ++func (f BoolFlag) name() string {return f.Name} ++func (f BoolFlag) usage() string {return f.Usage} ++func (f StringSliceFlag) name() string {return f.Name} ++func (f StringSliceFlag) usage() string {return f.Usage} ++ ++// takes a Flag with a comma delimited string ++// of flag names and returns the first one ++func canonicalName(flag Flag) string { ++ flagNames := strings.Split(flag.name(), ",") ++ return strings.TrimSpace(flagNames[0]) ++} ++ ++// takes a Flag with a comma delimited string ++// of flag names and returns them as a string slice ++// with the canonical (first) flag ommitted ++func alternateNames(flag Flag) []string { ++ flagNames := strings.Split(flag.name(), ",") ++ altNames := flagNames[1:] ++ for i, _ := range altNames { ++ altNames[i] = strings.TrimSpace(altNames[i]) ++ } ++ return altNames ++} ++ ++func isFlag(arg string) bool { ++ return strings.HasPrefix(arg, "-") ++} ++ ++func trimFlag(arg string) string { ++ return strings.Trim(strings.Trim(arg, "-"), "-") ++} ++ diff --git a/SOURCES/remove-fedora-dependency-automation.patch b/SOURCES/remove-fedora-dependency-automation.patch deleted file mode 100644 index be26c25..0000000 --- a/SOURCES/remove-fedora-dependency-automation.patch +++ /dev/null @@ -1,586 +0,0 @@ -diff --git a/rpm/fileattrs/go.attr b/rpm/fileattrs/go.attr -index d4d5761..a9000a7 100644 ---- a/rpm/fileattrs/go.attr -+++ b/rpm/fileattrs/go.attr -@@ -2,5 +2,3 @@ - - %__go_path ^%{gopath}/src/.+/.goipath$ - %__go_flags path --%__go_provides go-rpm-integration provides --prefix "%{buildroot}" --go-path "%{gopath}" %{?goprovflags} --%__go_requires go-rpm-integration requires --prefix "%{buildroot}" --go-path "%{gopath}" %{?goreqflags} -diff --git a/rpm/lua/rpm/go.lua b/rpm/lua/rpm/go.lua -index cb5f958..fb42cb7 100644 ---- a/rpm/lua/rpm/go.lua -+++ b/rpm/lua/rpm/go.lua -@@ -72,63 +72,6 @@ local function env(suffix, goipath, verbose, usermetadata) - fedora.explicitset( "currentgoldflags", ldflags, verbose) - end - ---- Create a single set of %install tasks for a known kind of Go subpackage --local function singleinstall(kind, suffix, verbose) -- local go = require "fedora.srpm.go" -- if (kind == "devel") then -- go.develenv(suffix, verbose) -- for goipath in string.gmatch(rpm.expand("%{currentgoipaths}"), "[^%s]+") do -- env('', goipath, verbose, {}) -- local vflag = verbose and " -v" or "" -- print(rpm.expand("%__godevelinstall -i " .. goipath .. vflag .. "\n")) -- end -- print(rpm.expand("%__godevelinstalldoc\n")) -- elseif (kind == "alt") then -- local fedora = require "fedora.common" -- local ismain = (suffix == "") or (suffix == "0") -- if ismain then -- fedora.zalias({"goaltipaths","gocid","goaltcid"}, verbose) -- end -- fedora.safeset("goaltcid" .. suffix, "%{?gocid" .. suffix .. "}", verbose) -- if ismain then -- fedora.zalias({"goaltcid"}, verbose) -- end -- for rpmname, goaltipaths in pairs(go.indexedgoipaths("%{goaltipaths" .. suffix .. "}", -- "%{goaltcid" .. suffix .. "}")) do -- go.altenv(suffix, rpmname, goaltipaths, verbose) -- gocanonipath = rpm.expand("%{currentgocanonipath}") -- for _, goaltipath in ipairs(goaltipaths) do -- fedora.explicitset("currentgoaltipath", goaltipath) -- print(rpm.expand("%__goaltinstall\n")) -- goaltipath = string.gsub(goaltipath, "/?[^/]+/?$", "") -- while (not string.match(gocanonipath, "^" .. goaltipath)) do -- print(rpm.expand('echo \'%dir "%{gopath}/src/' .. goaltipath .. '"\' >> "%{goworkdir}/%{currentgoaltfilelist}"\n')) -- goaltipath = string.gsub(goaltipath, "/?[^/]+/?$", "") -- end -- end -- end -- else -- rpm.expand("%{error:Unknown kind of Go subpackage: " .. kind .. "}") -- end --end -- ---- Create one or all %install tasks for a known kind of go subpackage --local function install(kind, suffix, processall, verbose) -- local fedora = require "fedora.common" -- local go = require "fedora.srpm.go" -- if (kind == "devel") then -- go.develenvinit() -- end -- if processall then -- for _, suffix in pairs(fedora.getsuffixes(go.pivot[kind])) do -- singleinstall(kind, suffix, verbose) -- end -- else -- singleinstall(kind, suffix, verbose) -- end --end -- - return { -- env = env, -- install = install, -+ env = env, - } -diff --git a/rpm/lua/srpm/go.lua b/rpm/lua/srpm/go.lua -index 457b8f1..d650b26 100644 ---- a/rpm/lua/srpm/go.lua -+++ b/rpm/lua/srpm/go.lua -@@ -232,104 +232,6 @@ local function altenv(suffix, rpmname, goaltipaths, verbose) - end - end - ---- Create a single %package section for a known kind of Go subpackage --local function singlepkg(kind, suffix, verbose) -- local fedora = require "fedora.common" -- if (kind == "devel") then -- develenv(suffix, verbose) -- print( -- rpm.expand( -- "%package -n %{currentgodevelname}\n" .. -- "Summary: %{currentgodevelsummary}\n" .. -- "BuildRequires: go-rpm-macros\n" .. -- "BuildArch: noarch\n" .. -- "%{?currentgodevelheader}\n" .. -- "%description -n %{currentgodevelname}\n") .. -- fedora.wordwrap("%{?currentgodeveldescription}") .. -- "\n") -- elseif (kind == "alt") then -- local ismain = (suffix == "") or (suffix == "0") -- if ismain then -- fedora.zalias({"goaltipaths","gocid","goaltcid"}, verbose) -- end -- fedora.safeset("goaltcid" .. suffix, "%{?gocid" .. suffix .. "}", verbose) -- if ismain then -- fedora.zalias({"goaltcid"}, verbose) -- end -- for rpmname, goaltipaths in pairs(indexedgoipaths("%{goaltipaths" .. suffix .. "}", -- "%{goaltcid" .. suffix .. "}")) do -- altenv(suffix, rpmname, goaltipaths, verbose) -- print( -- rpm.expand( -- "%package -n %{currentgoaltname}\n" .. -- "Summary: %{currentgoaltsummary}\n" .. -- "BuildRequires: go-rpm-macros\n" .. -- "BuildArch: noarch\n" .. -- "%{?currentgoaltheader}\n" .. -- "%description -n %{currentgoaltname}\n") .. -- fedora.wordwrap("%{?currentgoaltdescription}") .. -- "\n") -- end -- else -- rpm.expand("%{error:Unknown kind of Go subpackage: " .. kind .. "}") -- end --end -- ---- Create one or all %package sections for a known kind of go subpackage --local function pkg(kind, suffix, processall, verbose) -- local fedora = require "fedora.common" -- if (kind == "devel") then -- develenvinit() -- end -- if processall then -- for _, suffix in pairs(fedora.getsuffixes(pivot[kind])) do -- singlepkg(kind, suffix, verbose) -- end -- else -- singlepkg(kind, suffix, verbose) -- end --end -- ---- Create a single %files section for a known kind of Go subpackage --local function singlefiles(kind, suffix, verbose) -- if (kind == "devel") then -- develenv(suffix, verbose) -- print(rpm.expand('%files -n %{currentgodevelname} -f "%{goworkdir}/%{currentgodevelfilelist}"\n')) -- elseif (kind == "alt") then -- local fedora = require "fedora.common" -- local ismain = (suffix == "") or (suffix == "0") -- if ismain then -- fedora.zalias({"goaltipaths","gocid","goaltcid"}, verbose) -- end -- fedora.safeset("goaltcid" .. suffix, "%{?gocid" .. suffix .. "}", verbose) -- if ismain then -- fedora.zalias({"goaltcid"}, verbose) -- end -- for rpmname, goaltipaths in pairs(indexedgoipaths("%{goaltipaths" .. suffix .. "}", -- "%{goaltcid" .. suffix .. "}")) do -- altenv(suffix, rpmname, goaltipaths, verbose) -- print(rpm.expand('%files -n %{currentgoaltname} -f "%{goworkdir}/%{currentgoaltfilelist}"\n')) -- end -- else -- rpm.expand("%{error:Unknown kind of Go subpackage: " .. kind .. "}") -- end --end -- ---- Create one or all %files sections for a known kind of go subpackage --local function files(kind, suffix, processall, verbose) -- local fedora = require "fedora.common" -- if (kind == "devel") then -- develenvinit() -- end -- if processall then -- for _, suffix in pairs(fedora.getsuffixes(pivot[kind])) do -- singlefiles(kind, suffix, verbose) -- end -- else -- singlefiles(kind, suffix, verbose) -- end --end -- - return { - rpmname = rpmname, - meta = meta, -@@ -338,6 +240,5 @@ return { - develenvinit = develenvinit, - develenv = develenv, - altenv = altenv, -- pkg = pkg, -- files = files, - } -+ -diff --git a/rpm/macros.d/macros.go-compilers-golang b/rpm/macros.d/macros.go-compilers-golang -index b0ab4c4..942549f 100644 ---- a/rpm/macros.d/macros.go-compilers-golang -+++ b/rpm/macros.d/macros.go-compilers-golang -@@ -20,6 +20,8 @@ - # - # SPDX-License-Identifier: GPL-3.0-or-later - -+%gocompilerflags -buildmode pie -compiler gc -+ - # This *must* be all on one line, as it will be used in shell - # assignments. eg - # -@@ -29,22 +31,33 @@ - # - # %make GOBUILDFLAGS="%gobuildflags" - # --%gobuildflags() %{expand:%{gocompilerflags} -tags=\\"rpm_crashtraceback \\" -ldflags \\"${LDFLAGS:-}%{?currentgoldflags} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '%__global_ldflags %{?__golang_extldflags}'\\" -a -v -x} -+%gobuildflags() %{expand:%{gocompilerflags} -tags=\\"rpm_crashtraceback ${BUILDTAGS:-} libtrust_openssl\\" -ldflags \\"-linkmode=external -compressdwarf=false ${LDFLAGS:-}%{?currentgoldflags} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '%__global_ldflags %{?__golang_extldflags}'\\" -a -v -x} -+%_gobuildflags_internal() %{expand:%{gocompilerflags} -tags="rpm_crashtraceback ${BUILDTAGS:-} libtrust_openssl" -ldflags "-linkmode=external -compressdwarf=false ${LDFLAGS:-}%{?currentgoldflags} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '%__global_ldflags %{?__golang_extldflags}'" -a -v -x} - - # Turn off Go modules - %gomodulesmode GO111MODULE=off - - # Define commands for building - # BUILD_ID can be generated for golang build no matter of debuginfo -+ -+%_gobuild_cmd CGO_CPPFLAGS="-D_FORTIFY_SOURCE=2 -fstack-protector-all" go build %{_gobuildflags_internal} -+%gobuild_compat_el8(o:) %{expand:%{_gobuild_cmd} %{?**};} - %gobuild(o:) %{expand: - # https://bugzilla.redhat.com/show_bug.cgi?id=995136#c12 - %global _dwz_low_mem_die_limit 0 - %{?gobuilddir:GOPATH="%{gobuilddir}:${GOPATH:+${GOPATH}:}%{?gopath}"} %{?gomodulesmode} \\ -- go build %{?gocompilerflags} -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${LDFLAGS:-}%{?currentgoldflags} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '%__global_ldflags %{?__golang_extldflags}'" -a -v -x %{?**}; -+ %{_gobuild_cmd} %{?**}; - } - ${workroot}${GOPATH:+:${GOPATH}} - - # Define commands for testing - %gotestflags %{gocompilerflags} - %gotestextldflags %__global_ldflags %{?__golang_extldflags} --%gotest() %{?gomodulesmode} go test %{gotestflags} -ldflags "${LDFLAGS:-}%{?currentgoldflags} -extldflags '%{gotestextldflags}'" %{?**}; -+ -+%_gotest_cmd %{?gomodulesmode} go test %{gotestflags} -ldflags "${LDFLAGS:-}%{?currentgoldflags} -extldflags '%{gotestextldflags}'" -+%gotest_compat_el8(o:) %{expand:%{_gotest_cmd} %{?**};} -+%gotest(o:) %{expand: -+ %{?gobuilddir:GOPATH="%{gobuilddir}:${GOPATH:+${GOPATH}:}%{?gopath}"} %{?gomodulesmode} \\ -+ %{_gotest_cmd} %{?**}; -+} -+ -diff --git a/rpm/macros.d/macros.go-rpm b/rpm/macros.d/macros.go-rpm -index f773f34..b82581b 100644 ---- a/rpm/macros.d/macros.go-rpm -+++ b/rpm/macros.d/macros.go-rpm -@@ -22,42 +22,6 @@ - # - # SPDX-License-Identifier: GPL-3.0-or-later - --# Default filtering policy --# Complete or replace the following variables in your spec file if this policy --# does not apply to your project --# --# Specific example matching rule. --# The average Go project example code is incomplete and obsolete. It will --# fail to compile as-is, or even panic. It will poison the dependency --# generator with bogus or legacy import path requirements. Even when it it --# clean and up to date, it will require many third party components not needed --# in production. Therefore: --# – never install Go project example code in %{gopath}. Publish is as %doc. --# — ask politely projects that publish example code in some other directory --# than _examples to rename it. --# – never rely on third party examples being available or working in another --# project. This is *not* production code. Ask upstreams politely to remove --# tests or code that import other project examples. --%goignoreflags_examples -r '.*example.*' -- --# Default flags to apply in all stages --%godefaultflags %{goignoreflags_examples} -- --# Default flags to apply in Go install (%goinstall) --%goinstallflags %{godefaultflags} -- --# Default flags to apply in Go checks (%gochecks) --%gocheckflags %{godefaultflags} -- --# Default flags to apply in Go autoprovides --%goprovflags %{godefaultflags} -- --# Default flags to apply in Go autorequires --%goreqflags %{godefaultflags} -- --# The default filelist name generated by %goinstall --%gofilelist devel.file-list -- - # Sets environment variables suitable for a Go source archive. Optional arguments: - # -z read the zth block of definitions, for example - # %{goipath}, %{commit}… -@@ -116,6 +80,7 @@ fi - cd "%{mybuilddir}/src/%{mygoipath}" - } - -+ - # Perform usual Go source preparation steps. Optional arguments: - # -z read the zth block of definitions, for example - # %{goipath}, %{commit}… -@@ -160,207 +125,3 @@ else - process(rpm.expand("%{?-z*}")) - end - } -- --# Computes BuildRequires for a given import path. Arguments: --# -z read the zth block of definitions, for example --# %{goipath}, %{commit}… --# derived from the import path value if not specified --# -a process all sources in one go, instead of using separate --# -z calls --# -i use the specified import path value instead of the one --# found in %{goipath} --%go_generate_buildrequires(z:ai:) %{lua: --local fedora = require "fedora.common" --local processall = (rpm.expand("%{-a}") ~= "") and (rpm.expand("%{-z}") == "") --local forcedgoipath = rpm.expand("%{?-i}") --local golistargs = "" --if processall then -- for _, s in pairs(fedora.getsuffixes("goipath")) do -- golistargs = golistargs .. " --package-path %{goipath" .. s .. "}" -- end -- golistargs = string.gsub(golistargs, "^ ", "") --elseif forcedgoipath ~= "" then -- golistargs = "--package-path " .. forcedgoipath --else -- golistargs = "--package-path %{goipath" .. rpm.expand("%{?-z*}") .. "}" --end --print(rpm.expand('GOPATH="%{?gobuilddir:%{gobuilddir}:}${GOPATH:+${GOPATH}:}%{?gopath}" ' .. -- 'GO111MODULE=off ' .. -- "golist --imported " .. golistargs .. -- " --template 'golang({{.}})\\\\n'" .. -- " --with-tests --skip-self\\n")) --} -- --# Try to install Go package files in sensible locations, with strict directory --# ownership and lockfile creation as required by Go autodeps. --# --# Simple arguments, that can not be repeated: --# -z read the zth block of definitions, for example --# %{goipath}, %{commit}… --# derived from the import path value if not specified --# -a process all sources in one go, instead of using separate --# -z calls --# -i use the specified import path value --# default: %{goipath} --# -b read binaries already produced in --# default: %{gobuilddir}/bin --# -s read expanded and prepared Go sources in /src --# should be populated in %prep --# default: %{gobuilddir} --# -o output installed file list in --# default: %{gofilelist} --# -O output in --# -l add those flags to LDFLAGS when building unit tests --# -v be verbose --# --# Inclusion arguments, that can be repeated: --# -e include files with the provided extension --# --# Exclusion arguments, that can be repeated, relative to the go import path root: --# -d exclude the files contained in --# not recursive (subdirectories are not excluded) --# -t exclude the files contained in --# recursive (subdirectories are excluded) --# -r exclude files matching , --# --# Optional versionning metadata, that can not be repeated: --# -V Should only be specified when creating subpackages with --# distinct versions --# default: %{version}.%{release} --# -T default: %{tag} --# -C default: %{commit} --# -B default: %{branch} --# --# When invoked several times with the same import path goinstall will append to --# the existing file list if versionning and exclusion arguments are identical to --# previous calls, and error out otherwise. --# When invoked several times with different file list names, it will attribute --# directories to the first file list that makes use of them. --%goinstall(z:ai:b:s:o:O:ve:d:t:rV:T:C:B:p:g:) %{lua: --local fedora = require "fedora.common" --local processall = (rpm.expand("%{-a}") ~= "") and (rpm.expand("%{-z}") == "") --local myenvflags = rpm.expand('%{?-i} %{?-v} %{?-V} %{?-T} %{?-C} %{?-B}') --local myinstallflags = rpm.expand('%{!-i:-i "%%{currentgoipath}" }' .. -- '%{!-b:-b "%%{gobuilddir}/bin" }' .. -- '%{!-s:-s "%%{gobuilddir}" }' .. -- '%{!-o:-o "%%{thisgofilelist}" }' .. -- '%{!-O:-O "%%{goworkdir}" }' .. -- '%{!-V:-V "%{version}-%{release}" }' .. -- '%{!-T:%%{?currenttag: -T "%%{?currenttag}" }}' .. -- '%{!-C:%%{?currentcommit: -C "%%{?currentcommit}" }}' .. -- '%{!-B:%%{?currentbranch: -B "%%{?currentbranch}" }}' .. -- '%{!-p:-p "%{buildroot}" }' .. -- '%{!-g:-g "%{gopath}" }' .. -- '%{?goinstallflags} %{?**}') ---- Main function --local function process(suffix) -- local zsuffix = "" -- if (suffix ~= "") and (suffix ~= nil) then -- zsuffix = "-z " .. suffix .. " " -- end -- print(rpm.expand('%goenv ' .. zsuffix .. myenvflags .. '\\n' .. -- 'go-rpm-integration install ' .. myinstallflags .. '\\n')) --end ---- Main loop --if processall then -- for _,s in pairs(fedora.getsuffixes("goipath")) do -- process(s) -- end --else -- process(rpm.expand("%{-z*}")) --end --} -- --# Perform the %install tasks of every known kind of Go subpackage. Arguments: --# -v be verbose --%gopkginstall(av) %{expand: --%godevelinstall -a %{-v} --%goaltinstall -a %{-v} --} -- --# Perform the %install tasks of a golang-*-devel subpackage. Arguments: --# -z read the zth block of definitions, for example --# %{goipaths} --# -a process all blocks in one go, instead of using separate --# -z calls --# -v be verbose --%godevelinstall(z:av) %{lua: --local go = require "fedora.rpm.go" --local suffix = rpm.expand("%{-z*}") --local processall = (rpm.expand("%{-a}") ~= "") and (rpm.expand("%{-z}") == "") --local verbose = (rpm.expand("%{-v}") ~= "") --go.install("devel", suffix, processall, verbose) --} -- --# Perform the %install tasks of a compat-golang-*-devel subpackage. Arguments: --# -z read the zth block of definitions, for example --# %{goaltipaths} --# -a process all blocks in one go, instead of using separate --# -z calls --# -v be verbose --%goaltinstall(z:av) %{lua: --local go = require "fedora.rpm.go" --local suffix = rpm.expand("%{-z*}") --local processall = (rpm.expand("%{-a}") ~= "") and (rpm.expand("%{-z}") == "") --local verbose = (rpm.expand("%{-v}") ~= "") --go.install("alt", suffix, processall, verbose) --} -- --# Run go test with Fedora flags on all subdirectories except for those filtered out --# THIS MACRO IS OPT-OUT. --# --# Simple arguments, that can not be repeated: --# -z read the zth block of definitions, for example --# %{goipath}, %{commit}… --# derived from the import path value if not specified --# -a process all sources in one go, instead of using separate --# -z calls --# -i use the specified import path value --# default: %{goipath} --# -b read binaries already produced in --# default: %{gobuilddir}/bin --# -s read expanded and prepared Go sources in /src --# should be populated in %prep --# default: %{gobuilddir} --# -v be verbose --# Exclusion arguments, that can be repeated, relative to the go import path root: --# -d exclude the files contained in --# not recursive (subdirectories are not excluded) --# -t exclude the files contained in --# recursive (subdirectories are excluded) --# -r exclude files matching , --%gocheck(z:ai:b:s:vd:t:rV:T:C:B:p:g:w) %{lua: --local fedora = require "fedora.common" --local processall = (rpm.expand("%{-a}") ~= "") and (rpm.expand("%{-z}") == "") --local myenvflags = rpm.expand('%{?-i} %{?-v} %{?-V} %{?-T} %{?-C} %{?-B}') --local mycheckflags = rpm.expand('%{!-i:-i "%%{currentgoipath}" }' .. -- '%{!-b:-b "%%{gobuilddir}/bin" }' .. -- '%{!-s:-s "%%{gobuilddir}" }' .. -- '%{!-V:-V "%{version}-%{release}" }' .. -- '%{!-T:%%{?currenttag: -T "%%{?currenttag}" }}' .. -- '%{!-C:%%{?currentcommit: -C "%%{?currentcommit}" }}' .. -- '%{!-B:%%{?currentbranch: -B "%%{?currentbranch}" }}' .. -- '%{!-p:-p "%{buildroot}" }' .. -- '%{!-g:-g "%{gopath}" }' .. -- '%{?gocheckflags} %{?**}') ---- Main function --local function process(suffix) -- local zsuffix = "" -- if (suffix ~= "") and (suffix ~= nil) then -- zsuffix = "-z " .. suffix .. " " -- end -- print(rpm.expand('%goenv ' .. zsuffix .. myenvflags .. '\\n' .. -- '%{?currentgoldflags:LDFLAGS="${LDFLAGS} %{?currentgoldflags}" }' .. -- '%{?gotestflags:GO_TEST_FLAGS="%{gotestflags}" }' .. -- '%{?gotestextldflags:GO_TEST_EXT_LD_FLAGS="%{gotestextldflags}" }' .. -- 'go-rpm-integration check ' .. mycheckflags .. '\\n')) --end ---- Main loop --if processall then -- for _,s in pairs(fedora.getsuffixes("goipath")) do -- process(s) -- end --else -- process(rpm.expand("%{-z*}")) --end --} -diff --git a/rpm/macros.d/macros.go-srpm b/rpm/macros.d/macros.go-srpm -index 884463f..60b62ac 100644 ---- a/rpm/macros.d/macros.go-srpm -+++ b/rpm/macros.d/macros.go-srpm -@@ -122,72 +122,3 @@ else - end - } - --# Create %package sections for every known kind of go subpackage. Arguments: --# -v be verbose --%gopkg(av) %{expand: --%godevelpkg -a %{-v} --%goaltpkg -a %{-v} --} -- --# Create a %package section for a golang-*-devel subpackage. Arguments: --# -z read the zth block of definitions, for example --# %{goipaths} --# -a process all blocks in one go, instead of using separate --# -z calls --# -v be verbose --%godevelpkg(z:av) %{lua: --local go = require "fedora.srpm.go" --local suffix = rpm.expand("%{-z*}") --local processall = (rpm.expand("%{-a}") ~= "") and (rpm.expand("%{-z}") == "") --local verbose = (rpm.expand("%{-v}") ~= "") --go.pkg("devel", suffix, processall, verbose) --} -- --# Create a %package section for a compat-golang-*-devel subpackage. Arguments: --# -z read the zth block of definitions, for example --# %{goaltipaths} --# -a process all blocks in one go, instead of using separate --# -z calls --# -v be verbose --%goaltpkg(z:av) %{lua: --local go = require "fedora.srpm.go" --local suffix = rpm.expand("%{-z*}") --local processall = (rpm.expand("%{-a}") ~= "") and (rpm.expand("%{-z}") == "") --local verbose = (rpm.expand("%{-v}") ~= "") --go.pkg("alt", suffix, processall, verbose) --} -- --# Create %files sections for every known kind of Go subpackage. Arguments: --# -v be verbose --%gopkgfiles(av) %{expand: --%godevelfiles -a %{-v} --%goaltfiles -a %{-v} --} -- --# Create a %files section for a golang-*-devel subpackage. Arguments: --# -z read the zth block of definitions, for example --# %{goipaths} --# -a process all blocks in one go, instead of using separate --# -z calls --# -v be verbose --%godevelfiles(z:av) %{lua: --local go = require "fedora.srpm.go" --local suffix = rpm.expand("%{-z*}") --local processall = (rpm.expand("%{-a}") ~= "") and (rpm.expand("%{-z}") == "") --local verbose = (rpm.expand("%{-v}") ~= "") --go.files("devel", suffix, processall, verbose) --} -- --# Create a %files section for a compat-golang-*-devel subpackage. Arguments: --# -z read the zth block of definitions, for example --# %{goaltipaths} --# -a process all blocks in one go, instead of using separate --# -z calls --# -v be verbose --%goaltfiles(z:av) %{lua: --local go = require "fedora.srpm.go" --local suffix = rpm.expand("%{-z*}") --local processall = (rpm.expand("%{-a}") ~= "") and (rpm.expand("%{-z}") == "") --local verbose = (rpm.expand("%{-v}") ~= "") --go.files("alt", suffix, processall, verbose) --} diff --git a/SOURCES/update-default-gobuild-args.patch b/SOURCES/update-default-gobuild-args.patch new file mode 100644 index 0000000..2ca10c9 --- /dev/null +++ b/SOURCES/update-default-gobuild-args.patch @@ -0,0 +1,50 @@ +diff --git a/rpm/macros.d/macros.go-compilers-golang b/rpm/macros.d/macros.go-compilers-golang +index b0ab4c4..942549f 100644 +--- a/rpm/macros.d/macros.go-compilers-golang ++++ b/rpm/macros.d/macros.go-compilers-golang +@@ -20,6 +20,8 @@ + # + # SPDX-License-Identifier: GPL-3.0-or-later + ++%gocompilerflags -buildmode pie -compiler gc ++ + # This *must* be all on one line, as it will be used in shell + # assignments. eg + # +@@ -29,22 +31,33 @@ + # + # %make GOBUILDFLAGS="%gobuildflags" + # +-%gobuildflags() %{expand:%{gocompilerflags} -tags=\\"rpm_crashtraceback \\" -ldflags \\"${LDFLAGS:-}%{?currentgoldflags} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '%__global_ldflags %{?__golang_extldflags}'\\" -a -v -x} ++%gobuildflags() %{expand:%{gocompilerflags} -tags=\\"rpm_crashtraceback ${BUILDTAGS:-} libtrust_openssl\\" -ldflags \\"-linkmode=external -compressdwarf=false ${LDFLAGS:-}%{?currentgoldflags} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '%__global_ldflags %{?__golang_extldflags}'\\" -a -v -x} ++%_gobuildflags_internal() %{expand:%{gocompilerflags} -tags="rpm_crashtraceback ${BUILDTAGS:-} libtrust_openssl" -ldflags "-linkmode=external -compressdwarf=false ${LDFLAGS:-}%{?currentgoldflags} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '%__global_ldflags %{?__golang_extldflags}'" -a -v -x} + + # Turn off Go modules + %gomodulesmode GO111MODULE=off + + # Define commands for building + # BUILD_ID can be generated for golang build no matter of debuginfo ++ ++%_gobuild_cmd CGO_CPPFLAGS="-D_FORTIFY_SOURCE=2 -fstack-protector-all" go build %{_gobuildflags_internal} ++%gobuild_compat_el8(o:) %{expand:%{_gobuild_cmd} %{?**};} + %gobuild(o:) %{expand: + # https://bugzilla.redhat.com/show_bug.cgi?id=995136#c12 + %global _dwz_low_mem_die_limit 0 + %{?gobuilddir:GOPATH="%{gobuilddir}:${GOPATH:+${GOPATH}:}%{?gopath}"} %{?gomodulesmode} \\ +- go build %{?gocompilerflags} -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${LDFLAGS:-}%{?currentgoldflags} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '%__global_ldflags %{?__golang_extldflags}'" -a -v -x %{?**}; ++ %{_gobuild_cmd} %{?**}; + } + ${workroot}${GOPATH:+:${GOPATH}} + + # Define commands for testing + %gotestflags %{gocompilerflags} + %gotestextldflags %__global_ldflags %{?__golang_extldflags} +-%gotest() %{?gomodulesmode} go test %{gotestflags} -ldflags "${LDFLAGS:-}%{?currentgoldflags} -extldflags '%{gotestextldflags}'" %{?**}; ++ ++%_gotest_cmd %{?gomodulesmode} go test %{gotestflags} -ldflags "${LDFLAGS:-}%{?currentgoldflags} -extldflags '%{gotestextldflags}'" ++%gotest_compat_el8(o:) %{expand:%{_gotest_cmd} %{?**};} ++%gotest(o:) %{expand: ++ %{?gobuilddir:GOPATH="%{gobuilddir}:${GOPATH:+${GOPATH}:}%{?gopath}"} %{?gomodulesmode} \\ ++ %{_gotest_cmd} %{?**}; ++} ++ diff --git a/SPECS/go-rpm-macros.spec b/SPECS/go-rpm-macros.spec index e8d1e14..6c5c694 100644 --- a/SPECS/go-rpm-macros.spec +++ b/SPECS/go-rpm-macros.spec @@ -17,20 +17,42 @@ Version: 3.0.9 # make Go devel packages archful %global gopath %{_datadir}/gocode +# whether to bundle golist or require it as a dependency +%global bundle_golist 1 + +%if 0%{?bundle_golist} +# do not create debuginfo packages when we add a build section +%global debug_package %{nil} +%global golist_version 0.10.1 +%global golist_builddir %{_builddir}/golist-%{golist_version}/_build +%global golist_goipath pagure.io/golist +# where to bundle the golist executable +%global golist_execdir %{_libexecdir}/go-rpm-macros/ +# define gobuild to avoid this package requiring itself to build +%define gobuild(o:) GO111MODULE=off go build -buildmode pie -compiler gc -tags="rpm_crashtraceback ${BUILDTAGS:-}" -ldflags "${LDFLAGS:-} -B 0x$(head -c20 /dev/urandom|od -An -tx1|tr -d ' \\n') -extldflags '-Wl,-z,relro -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld '" -a -v %{?**}; +%endif + ExclusiveArch: %{golang_arches} %{gccgo_arches} Name: go-rpm-macros -Release: 8%{?dist} +Release: 9%{?dist} Summary: Build-stage rpm automation for Go packages License: GPLv3+ URL: %{forgeurl} -Source: %{forgesource} +Source0: %{forgesource} +%if 0%{?bundle_golist} +Source1: https://pagure.io/golist/archive/v%{golist_version}/golist-%{golist_version}.tar.gz +%endif Requires: go-srpm-macros = %{version}-%{release} Requires: go-filesystem = %{version}-%{release} -Patch0: remove-fedora-dependency-automation.patch +%if 0%{?bundle_golist} +BuildRequires: golang +%else +Requires: golist +%endif %ifarch %{golang_arches} Requires: golang @@ -46,6 +68,12 @@ Provides: compiler(go-compiler) = 1 Obsoletes: go-compilers-gcc-go-compiler < %{version}-%{release} %endif +Patch0: update-default-gobuild-args.patch +# Replace golang-github-urfave-cli with a minimal +# command line parser backend to bootstrap golist +# without dependencies. +Patch1: golist-bootstrap-cli-no-vendor.patch + %description This package provides build-stage rpm automation to simplify the creation of Go language (golang) packages. @@ -88,45 +116,48 @@ This package contains documented rpm spec templates showcasing how to use the macros provided by go-rpm-macros to create Go packages. %prep - %forgesetup -# remove fedora-specific macros and templates %patch0 -p1 -DELETE_FILES=$( - cat << EOF - bin/go-rpm-integration - rpm/fileattrs/gobundled.attr - rpm/fileattrs/gosymlink.attr - rpm/gobundled.prov - rpm/gosymlink.deps - rpm/macros.d/macros.go-compilers-golang-nopie - rpm/macros.d/macros.go-compilers-golang-pie - rpm/macros.d/macros.go-rpm.internal - templates/rpm/spectemplate-go-0-source-minimal.spec - templates/rpm/spectemplate-go-1-source-full.spec - templates/rpm/spectemplate-go-2-alternative-import-path-minimal.spec - templates/rpm/spectemplate-go-3-alternative-import-path-full.spec - templates/rpm/spectemplate-go-4-binary-minimal.spec - templates/rpm/spectemplate-go-5-binary-full.spec - templates/rpm/spectemplate-go-6-multi.spec - templates/rpm/spectemplate-go-7-manual.spec -EOF -) -for i in $DELETE_FILES; do - rm --interactive=never $i -done -# these directories should now be empty -rmdir -p bin templates/rpm %writevars -f rpm/macros.d/macros.go-srpm golang_arches gccgo_arches gopath -if ls templates/rpm/*\.spec; then - for template in templates/rpm/*\.spec ; do - target=$(echo "${template}" | sed "s|^\(.*\)\.spec$|\1-bare.spec|g") - grep -v '^#' "${template}" > "${target}" - touch -r "${template}" "${target}" - done +for template in templates/rpm/*\.spec ; do + target=$(echo "${template}" | sed "s|^\(.*\)\.spec$|\1-bare.spec|g") + grep -v '^#' "${template}" > "${target}" + touch -r "${template}" "${target}" +done + +# unpack golist and patch +%if 0%{?bundle_golist} +pushd %{_builddir} +tar -xf %{_sourcedir}/golist-%{golist_version}.tar.gz +cd golist-%{golist_version} +%patch1 -p1 +cp %{_builddir}/golist-%{golist_version}/LICENSE %{_builddir}/go-rpm-macros-%{version}/LICENSE-golist +popd + +# create directory structure for a Go build +if [[ ! -e %{golist_builddir}/bin ]]; then + install -m 0755 -vd %{golist_builddir}/bin + export GOPATH=%{golist_builddir}:${GOPATH:+${GOPATH}:}/usr/share/gocode fi +if [[ ! -e %{golist_builddir}/src/%{golist_goipath} ]]; then + install -m 0755 -vd %{golist_builddir}/src/pagure.io + ln -sf $(dirname %{golist_builddir}) %{golist_builddir}/src/%{golist_goipath} + +fi +%endif + +%build +# build golist +%if 0%{?bundle_golist} +pushd %{golist_builddir}/src/%{golist_goipath} +export GOPATH=%{golist_builddir}:${GOPATH:+${GOPATH}:}/usr/share/gocode +for cmd in cmd/* ; do + %gobuild -o %{golist_builddir}/bin/$(basename $cmd) %{golist_goipath}/$cmd +done +popd +%endif %install # Some of those probably do not work with gcc-go right now @@ -142,6 +173,9 @@ if ls templates/rpm/*\.spec; then %{buildroot}%{_spectemplatedir} fi +install -m 0755 -vd %{buildroot}%{_bindir} +install -m 0755 bin/* %{buildroot}%{_bindir} + install -m 0755 -vd %{buildroot}%{rpmmacrodir} install -m 0644 -vp rpm/macros.d/macros.go-* \ %{buildroot}%{rpmmacrodir} @@ -154,6 +188,8 @@ install -m 0644 -vp rpm/lua/rpm/*lua \ install -m 0755 -vd %{buildroot}%{_rpmconfigdir}/fileattrs install -m 0644 -vp rpm/fileattrs/*.attr \ %{buildroot}%{_rpmconfigdir}/fileattrs/ +install -m 0755 -vp rpm/*\.{prov,deps} \ + %{buildroot}%{_rpmconfigdir}/ %ifarch %{golang_arches} install -m 0644 -vp rpm/macros.d/macros.go-compilers-golang \ @@ -165,13 +201,27 @@ install -m 0644 -vp rpm/macros.d/macros.go-compilers-gcc \ %{buildroot}%{_rpmconfigdir}/macros.d/macros.go-compiler-gcc %endif +# install golist +%if 0%{?bundle_golist} +install -m 0755 -vd %{buildroot}%{golist_execdir} +install -m 0755 -vp %{golist_builddir}/bin/* %{buildroot}%{golist_execdir}/ +sed -i "s,golist,%{golist_execdir}/golist,g" %{buildroot}%{_bindir}/go-rpm-integration +%endif + %files -%license LICENSE.txt +%license LICENSE.txt LICENSE-golist %doc README.md +%{_bindir}/* %{_rpmconfigdir}/fileattrs/*.attr +%{_rpmconfigdir}/*.prov +%{_rpmconfigdir}/*.deps %{_rpmconfigdir}/macros.d/macros.go-rpm* %{_rpmconfigdir}/macros.d/macros.go-compiler* %{_rpmluadir}/fedora/rpm/*.lua +# package golist +%if 0%{?bundle_golist} +%{golist_execdir}/golist +%endif %files -n go-srpm-macros %license LICENSE.txt @@ -189,13 +239,19 @@ install -m 0644 -vp rpm/macros.d/macros.go-compilers-gcc \ # https://src.fedoraproject.org/rpms/redhat-rpm-config/pull-request/51 %dir %{dirname:%{_spectemplatedir}} %dir %{_spectemplatedir} +%{_spectemplatedir}/*.spec %changelog +* Tue Jan 18 2022 David Benoit 3.0.9-9 +- Delete remove-fedora-dependency-automation.patch +- Bundle golist in /usr/libexec +- Related: rhbz#2043107 + * Mon Aug 09 2021 Mohan Boddu - Rebuilt for IMA sigs, glibc 2.34, aarch64 flags Related: rhbz#1991688 -* Wed Aug 03 2021 David Benoit 3.0.9-7 +* Tue Aug 03 2021 David Benoit 3.0.9-7 - Escape quotation marks in gobuildflags - Resolves: rhbz#1988717