@@ -13,13 +13,14 @@ import (
1313 "os"
1414 "path"
1515 "path/filepath"
16+ "regexp"
1617 "strings"
1718 "time"
1819
1920 "github.com/magefile/mage/mg"
2021 "golang.org/x/sync/errgroup"
2122
22- "github.com/elastic/elastic-agent/dev-tools/mage/pkgcommon "
23+ "github.com/elastic/elastic-agent/dev-tools/packaging "
2324 "github.com/elastic/elastic-agent/pkg/version"
2425)
2526
@@ -94,6 +95,7 @@ var PlatformPackages = map[string]string{
9495 "windows/amd64" : "windows-x86_64.zip" ,
9596}
9697
98+ << << << < HEAD
9799// ExpectedBinaries is a map of binaries agent needs to their project in the unified-release manager.
98100// The project names are those used in the "projects" list in the unified release manifest.
99101// See the sample manifests in the testdata directory.
@@ -161,6 +163,8 @@ func (p Platform) Platform() string {
161163
162164var AllPlatforms = []Platform {{"linux" , "x86_64" }, {"linux" , "arm64" }, {"windows" , "x86_64" }, {"darwin" , "x86_64" }, {"darwin" , "aarch64" }}
163165
166+ == == == =
167+ >> >> >> > 894 ef9385 (Make components in packages configurable (#7602 ))
164168// DownloadManifest is going to download the given manifest file and return the ManifestResponse
165169func DownloadManifest (ctx context.Context , manifest string ) (Build , error ) {
166170 manifestUrl , urlError := url .Parse (manifest )
@@ -211,7 +215,7 @@ func DownloadComponents(ctx context.Context, manifest string, platforms []string
211215
212216 errGrp , downloadsCtx := errgroup .WithContext (ctx )
213217 // for project, pkgs := range expectedProjectPkgs() {
214- for _ , spec := range ExpectedBinaries {
218+ for _ , spec := range packaging . ExpectedBinaries {
215219 for _ , platform := range platforms {
216220 targetPath := filepath .Join (dropPath )
217221 err := os .MkdirAll (targetPath , 0755 )
@@ -225,12 +229,12 @@ func DownloadComponents(ctx context.Context, manifest string, platforms []string
225229 continue
226230 }
227231
228- pkgURL , err := resolveManifestPackage (projects [spec .ProjectName ], spec , majorMinorPatchVersion , platform )
232+ resolvedPackage , err := ResolveManifestPackage (projects [spec .ProjectName ], spec , majorMinorPatchVersion , platform )
229233 if err != nil {
230234 return err
231235 }
232236
233- for _ , p := range pkgURL {
237+ for _ , p := range resolvedPackage . URLs {
234238 log .Printf (">>>>>>>>> Downloading [%s] [%s] " , spec .BinaryName , p )
235239 pkgFilename := path .Base (p )
236240 downloadTarget := filepath .Join (targetPath , pkgFilename )
@@ -252,76 +256,114 @@ func DownloadComponents(ctx context.Context, manifest string, platforms []string
252256 return nil
253257}
254258
255- func resolveManifestPackage (project Project , spec BinarySpec , version string , platform string ) ([]string , error ) {
256- var val Package
257- var ok bool
259+ type ResolvedPackage struct {
260+ Name string
261+ URLs []string
262+ }
263+
264+ func ResolveManifestPackage (project Project , spec packaging.BinarySpec , dependencyVersion string , platform string ) (* ResolvedPackage , error ) {
258265
259266 // Try the normal/easy case first
260- packageName := spec .GetPackageName (version , platform )
261- val , ok = project .Packages [packageName ]
262- if ! ok {
263- // If we didn't find it, it may be an Independent Agent Release, where
264- // the opted-in projects will have a patch version one higher than
265- // the rest of the projects, so we need to seek that out
267+ packageName := spec .GetPackageName (dependencyVersion , platform )
268+ if mg .Verbose () {
269+ log .Printf (">>>>>>>>>>> Got packagename [%s], looking for exact match" , packageName )
270+ }
271+
272+ if exactMatch , ok := project .Packages [packageName ]; ok {
273+ // We found the exact filename we are looking for
266274 if mg .Verbose () {
267- log .Printf (">>>>>>>>>>> Looking for package [%s] of type [ %s]" , spec . BinaryName , PlatformPackages [ platform ] )
275+ log .Printf (">>>>>>>>>>> Found exact match packageName for [%s, %s]: %s " , project . Branch , project . CommitHash , exactMatch )
268276 }
269277
270- var foundIt bool
271- for pkgName := range project .Packages {
272- if strings .HasPrefix (pkgName , spec .BinaryName ) {
273- firstSplit := strings .Split (pkgName , spec .BinaryName + "-" )
274- if len (firstSplit ) < 2 {
275- continue
276- }
278+ return & ResolvedPackage {
279+ Name : packageName ,
280+ URLs : []string {exactMatch .URL , exactMatch .ShaURL , exactMatch .AscURL },
281+ }, nil
282+ }
277283
278- secondHalf := firstSplit [1 ]
279- // Make sure we're finding one w/ the same required package type
280- if strings .Contains (secondHalf , PlatformPackages [platform ]) {
281-
282- // Split again after the version with the required package string
283- secondSplit := strings .Split (secondHalf , "-" + PlatformPackages [platform ])
284- if len (secondSplit ) < 2 {
285- continue
286- }
287-
288- // The first element after the split should normally be the version
289- pkgVersion := secondSplit [0 ]
290- if mg .Verbose () {
291- log .Printf (">>>>>>>>>>> Using derived version for package [%s]: %s " , pkgName , pkgVersion )
292- }
293-
294- // Create a project/package key with the package, derived version, and required package
295- foundPkgKey := fmt .Sprintf ("%s-%s-%s" , spec .BinaryName , pkgVersion , PlatformPackages [platform ])
296- if mg .Verbose () {
297- log .Printf (">>>>>>>>>>> Looking for project package key: [%s]" , foundPkgKey )
298- }
299-
300- // Get the package value, if it exists
301- val , ok = project .Packages [foundPkgKey ]
302- if ! ok {
303- continue
304- }
305-
306- if mg .Verbose () {
307- log .Printf (">>>>>>>>>>> Found package key [%s]" , foundPkgKey )
308- }
309-
310- foundIt = true
311- }
312- }
313- }
284+ // If we didn't find it, it may be an Independent Agent Release, where
285+ // the opted-in projects will have a patch version one higher than
286+ // the rest of the projects, so we "relax" the version constraint
314287
315- if ! foundIt {
316- return nil , fmt .Errorf ("package [%s] not found in project manifest at %s" , packageName , project .ExternalArtifactsManifestURL )
317- }
288+ // Find the original version in the filename
289+ versionIndex := strings .Index (packageName , dependencyVersion )
290+ if versionIndex == - 1 {
291+ return nil , fmt .Errorf ("no exact match and filename %q does not seem to contain dependencyVersion %q to try a fallback" , packageName , dependencyVersion )
292+ }
293+
294+ // TODO move relaxVersion to the version package so we can rewrite the version like so
295+ //parseVersion, _ := version.ParseVersion(dependencyVersion)
296+ //parseVersion.GetRelaxedPatchRegexp()
297+ relaxedVersion , err := relaxVersion (dependencyVersion )
298+ if err != nil {
299+ return nil , fmt .Errorf ("relaxing dependencyVersion %q: %w" , dependencyVersion , err )
300+ }
301+
302+ if mg .Verbose () {
303+ log .Printf (">>>>>>>>>>> Couldn't find exact match, relaxing agent dependencyVersion to %s" , relaxedVersion )
318304 }
319305
306+ // locate the original version in the filename and substitute the relaxed version regexp, quoting everything around that
307+ relaxedPackageName := regexp .QuoteMeta (packageName [:versionIndex ])
308+ relaxedPackageName += relaxedVersion
309+ relaxedPackageName += regexp .QuoteMeta (packageName [versionIndex + len (dependencyVersion ):])
310+
320311 if mg .Verbose () {
321- log .Printf (">>>>>>>>>>> Project branch/commit [%s, %s] " , project . Branch , project . CommitHash )
312+ log .Printf (">>>>>>>>>>> Attempting to match a filename with %s " , relaxedPackageName )
322313 }
323314
324- return []string {val .URL , val .ShaURL , val .AscURL }, nil
315+ relaxedPackageNameRegexp , err := regexp .Compile (relaxedPackageName )
316+ if err != nil {
317+ return nil , fmt .Errorf ("compiling relaxed package name regex %q: %w" , relaxedPackageName , err )
318+ }
319+
320+ for pkgName , pkg := range project .Packages {
321+ if mg .Verbose () {
322+ log .Printf (">>>>>>>>>>> Evaluating filename %s" , pkgName )
323+ }
324+ if relaxedPackageNameRegexp .MatchString (pkgName ) {
325+ if mg .Verbose () {
326+ log .Printf (">>>>>>>>>>> Found matching packageName for [%s, %s]: %s" , project .Branch , project .CommitHash , pkgName )
327+ }
328+ return & ResolvedPackage {
329+ Name : pkgName ,
330+ URLs : []string {pkg .URL , pkg .ShaURL , pkg .AscURL },
331+ }, nil
332+ }
333+ }
334+
335+ return nil , fmt .Errorf ("package [%s] not found in project manifest at %s" , packageName , project .ExternalArtifactsManifestURL )
336+ }
337+
338+ // versionRegexp is taken from https://semver.org/ (see the FAQ section/Is there a suggested regular expression (RegEx) to check a SemVer string?)
339+ const versionRegexp = `^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(0|[1-9]\d*)(?:-(?:(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?:[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`
340+ const anyPatchVersionRegexp = `(?:0|[1-9]\d*)`
341+
342+ var versionRegExp = regexp .MustCompile (versionRegexp )
343+
344+ func relaxVersion (version string ) (string , error ) {
345+ matchIndices := versionRegExp .FindSubmatchIndex ([]byte (version ))
346+ // Matches index pairs are (0,1) for the whole regexp and (2,3) for the patch group
347+ // check that we have matched correctly
348+ if len (matchIndices ) < 4 {
349+ return "" , fmt .Errorf ("failed to match regexp for version [%s]" , version )
350+ }
351+
352+ // take the starting index of the patch version
353+ patchStartIndex := matchIndices [2 ]
354+ // copy everything before the patch version escaping the regexp
355+ relaxedVersion := regexp .QuoteMeta (version [:patchStartIndex ])
356+ // add the patch regexp
357+ relaxedVersion += anyPatchVersionRegexp
358+ // check if there's more characters after the patch version
359+ remainderIndex := matchIndices [3 ]
360+ if remainderIndex < len (version ) {
361+ // This is a looser regexp that allows anything beyond the major version to change (while still enforcing a valid patch version though)
362+ // see TestResolveManifestPackage/Independent_Agent_Staging_8.14_apm-server and TestResolveManifestPackage/Independent_Agent_Staging_8.14_endpoint-dev
363+ // Be more relaxed and allow for any character sequence after this
364+ relaxedVersion += `.*`
365+ }
366+ return relaxedVersion , nil
325367}
326368
327369func DownloadPackage (ctx context.Context , downloadUrl string , target string ) error {
0 commit comments