@@ -32,127 +32,136 @@ func CleanupTask(ctx context.Context, olderThan time.Duration) error {
3232	return  CleanupExpiredData (ctx , olderThan )
3333}
3434
35- func  ExecuteCleanupRules (outerCtx  context.Context ) error  {
36- 	ctx , committer , err  :=  db .TxContext (outerCtx )
35+ func  executeCleanupOneRulePackage (ctx  context.Context , pcr  * packages_model.PackageCleanupRule , p  * packages_model.Package ) (versionDeleted  bool , err  error ) {
36+ 	olderThan  :=  time .Now ().AddDate (0 , 0 , - pcr .RemoveDays )
37+ 	pvs , _ , err  :=  packages_model .SearchVersions (ctx , & packages_model.PackageSearchOptions {
38+ 		PackageID :  p .ID ,
39+ 		IsInternal : optional .Some (false ),
40+ 		Sort :       packages_model .SortCreatedDesc ,
41+ 	})
3742	if  err  !=  nil  {
38- 		return  err 
43+ 		return  false ,  fmt . Errorf ( "CleanupRule [%d]: SearchVersions failed: %w" ,  pcr . ID ,  err ) 
3944	}
40- 	defer  committer .Close ()
41- 
42- 	err  =  packages_model .IterateEnabledCleanupRules (ctx , func (ctx  context.Context , pcr  * packages_model.PackageCleanupRule ) error  {
43- 		select  {
44- 		case  <- outerCtx .Done ():
45- 			return  db .ErrCancelledf ("While processing package cleanup rules" )
46- 		default :
45+ 	if  pcr .KeepCount  >  0  {
46+ 		if  pcr .KeepCount  <  len (pvs ) {
47+ 			pvs  =  pvs [pcr .KeepCount :]
48+ 		} else  {
49+ 			pvs  =  nil 
4750		}
48- 
49- 		if  err  :=  pcr .CompiledPattern (); err  !=  nil  {
50- 			return  fmt .Errorf ("CleanupRule [%d]: CompilePattern failed: %w" , pcr .ID , err )
51+ 	}
52+ 	for  _ , pv  :=  range  pvs  {
53+ 		if  pcr .Type  ==  packages_model .TypeContainer  {
54+ 			if  skip , err  :=  container_service .ShouldBeSkipped (ctx , pcr , p , pv ); err  !=  nil  {
55+ 				return  false , fmt .Errorf ("CleanupRule [%d]: container.ShouldBeSkipped failed: %w" , pcr .ID , err )
56+ 			} else  if  skip  {
57+ 				log .Debug ("Rule[%d]: keep '%s/%s' (container)" , pcr .ID , p .Name , pv .Version )
58+ 				continue 
59+ 			}
5160		}
52- 
53- 		olderThan  :=  time .Now ().AddDate (0 , 0 , - pcr .RemoveDays )
54- 
55- 		packages , err  :=  packages_model .GetPackagesByType (ctx , pcr .OwnerID , pcr .Type )
56- 		if  err  !=  nil  {
57- 			return  fmt .Errorf ("CleanupRule [%d]: GetPackagesByType failed: %w" , pcr .ID , err )
61+ 		toMatch  :=  pv .LowerVersion 
62+ 		if  pcr .MatchFullName  {
63+ 			toMatch  =  p .LowerName  +  "/"  +  pv .LowerVersion 
64+ 		}
65+ 		if  pcr .KeepPatternMatcher  !=  nil  &&  pcr .KeepPatternMatcher .MatchString (toMatch ) {
66+ 			log .Debug ("Rule[%d]: keep '%s/%s' (keep pattern)" , pcr .ID , p .Name , pv .Version )
67+ 			continue 
68+ 		}
69+ 		if  pv .CreatedUnix .AsLocalTime ().After (olderThan ) {
70+ 			log .Debug ("Rule[%d]: keep '%s/%s' (remove days) %v" , pcr .ID , p .Name , pv .Version , pv .CreatedUnix .FormatDate ())
71+ 			continue 
5872		}
73+ 		if  pcr .RemovePatternMatcher  !=  nil  &&  ! pcr .RemovePatternMatcher .MatchString (toMatch ) {
74+ 			log .Debug ("Rule[%d]: keep '%s/%s' (remove pattern)" , pcr .ID , p .Name , pv .Version )
75+ 			continue 
76+ 		}
77+ 		log .Debug ("Rule[%d]: remove '%s/%s'" , pcr .ID , p .Name , pv .Version )
78+ 		if  err  :=  packages_service .DeletePackageVersionAndReferences (ctx , pv ); err  !=  nil  {
79+ 			log .Error ("CleanupRule [%d]: DeletePackageVersionAndReferences failed: %v" , pcr .ID , err )
80+ 			continue 
81+ 		}
82+ 		versionDeleted  =  true 
83+ 	}
84+ 	return  versionDeleted , nil 
85+ }
5986
60- 		anyVersionDeleted  :=  false 
61- 		for  _ , p  :=  range  packages  {
62- 			pvs , _ , err  :=  packages_model .SearchVersions (ctx , & packages_model.PackageSearchOptions {
63- 				PackageID :  p .ID ,
64- 				IsInternal : optional .Some (false ),
65- 				Sort :       packages_model .SortCreatedDesc ,
66- 				Paginator :  db .NewAbsoluteListOptions (pcr .KeepCount , 200 ),
67- 			})
68- 			if  err  !=  nil  {
69- 				return  fmt .Errorf ("CleanupRule [%d]: SearchVersions failed: %w" , pcr .ID , err )
70- 			}
71- 			versionDeleted  :=  false 
72- 			for  _ , pv  :=  range  pvs  {
73- 				if  pcr .Type  ==  packages_model .TypeContainer  {
74- 					if  skip , err  :=  container_service .ShouldBeSkipped (ctx , pcr , p , pv ); err  !=  nil  {
75- 						return  fmt .Errorf ("CleanupRule [%d]: container.ShouldBeSkipped failed: %w" , pcr .ID , err )
76- 					} else  if  skip  {
77- 						log .Debug ("Rule[%d]: keep '%s/%s' (container)" , pcr .ID , p .Name , pv .Version )
78- 						continue 
79- 					}
80- 				}
87+ func  executeCleanupOneRule (ctx  context.Context , pcr  * packages_model.PackageCleanupRule ) error  {
88+ 	if  err  :=  pcr .CompiledPattern (); err  !=  nil  {
89+ 		return  fmt .Errorf ("CleanupRule [%d]: CompilePattern failed: %w" , pcr .ID , err )
90+ 	}
8191
82- 				 toMatch   :=  pv . LowerVersion 
83- 				 if  pcr . MatchFullName  {
84- 					 toMatch   =   p . LowerName   +   "/"   +   pv . LowerVersion 
85- 				 }
92+ 	packages ,  err   :=  packages_model . GetPackagesByType ( ctx ,  pcr . OwnerID ,  pcr . Type ) 
93+ 	if  err   !=   nil  {
94+ 		return   fmt . Errorf ( "CleanupRule [%d]: GetPackagesByType failed: %w" ,  pcr . ID ,  err ) 
95+ 	}
8696
87- 				if  pcr .KeepPatternMatcher  !=  nil  &&  pcr .KeepPatternMatcher .MatchString (toMatch ) {
88- 					log .Debug ("Rule[%d]: keep '%s/%s' (keep pattern)" , pcr .ID , p .Name , pv .Version )
89- 					continue 
90- 				}
91- 				if  pv .CreatedUnix .AsLocalTime ().After (olderThan ) {
92- 					log .Debug ("Rule[%d]: keep '%s/%s' (remove days)" , pcr .ID , p .Name , pv .Version )
93- 					continue 
94- 				}
95- 				if  pcr .RemovePatternMatcher  !=  nil  &&  ! pcr .RemovePatternMatcher .MatchString (toMatch ) {
96- 					log .Debug ("Rule[%d]: keep '%s/%s' (remove pattern)" , pcr .ID , p .Name , pv .Version )
97- 					continue 
97+ 	anyVersionDeleted  :=  false 
98+ 	for  _ , p  :=  range  packages  {
99+ 		versionDeleted  :=  false 
100+ 		err  =  db .WithTx (ctx , func (ctx  context.Context ) (err  error ) {
101+ 			versionDeleted , err  =  executeCleanupOneRulePackage (ctx , pcr , p )
102+ 			return  err 
103+ 		})
104+ 		if  err  !=  nil  {
105+ 			log .Error ("CleanupRule [%d]: executeCleanupOneRulePackage(%d) failed: %v" , pcr .ID , p .ID , err )
106+ 			continue 
107+ 		}
108+ 		anyVersionDeleted  =  anyVersionDeleted  ||  versionDeleted 
109+ 		if  versionDeleted  {
110+ 			if  pcr .Type  ==  packages_model .TypeCargo  {
111+ 				owner , err  :=  user_model .GetUserByID (ctx , pcr .OwnerID )
112+ 				if  err  !=  nil  {
113+ 					return  fmt .Errorf ("GetUserByID failed: %w" , err )
98114				}
99- 
100- 				log .Debug ("Rule[%d]: remove '%s/%s'" , pcr .ID , p .Name , pv .Version )
101- 
102- 				if  err  :=  packages_service .DeletePackageVersionAndReferences (ctx , pv ); err  !=  nil  {
103- 					return  fmt .Errorf ("CleanupRule [%d]: DeletePackageVersionAndReferences failed: %w" , pcr .ID , err )
115+ 				if  err  :=  cargo_service .UpdatePackageIndexIfExists (ctx , owner , owner , p .ID ); err  !=  nil  {
116+ 					return  fmt .Errorf ("CleanupRule [%d]: cargo.UpdatePackageIndexIfExists failed: %w" , pcr .ID , err )
104117				}
118+ 			}
119+ 		}
120+ 	}
105121
106- 				versionDeleted  =  true 
107- 				anyVersionDeleted  =  true 
122+ 	if  anyVersionDeleted  {
123+ 		switch  pcr .Type  {
124+ 		case  packages_model .TypeDebian :
125+ 			if  err  :=  debian_service .BuildAllRepositoryFiles (ctx , pcr .OwnerID ); err  !=  nil  {
126+ 				return  fmt .Errorf ("CleanupRule [%d]: debian.BuildAllRepositoryFiles failed: %w" , pcr .ID , err )
127+ 			}
128+ 		case  packages_model .TypeAlpine :
129+ 			if  err  :=  alpine_service .BuildAllRepositoryFiles (ctx , pcr .OwnerID ); err  !=  nil  {
130+ 				return  fmt .Errorf ("CleanupRule [%d]: alpine.BuildAllRepositoryFiles failed: %w" , pcr .ID , err )
108131			}
132+ 		case  packages_model .TypeRpm :
133+ 			if  err  :=  rpm_service .BuildAllRepositoryFiles (ctx , pcr .OwnerID ); err  !=  nil  {
134+ 				return  fmt .Errorf ("CleanupRule [%d]: rpm.BuildAllRepositoryFiles failed: %w" , pcr .ID , err )
135+ 			}
136+ 		case  packages_model .TypeArch :
137+ 			release , err  :=  arch_service .AquireRegistryLock (ctx , pcr .OwnerID )
138+ 			if  err  !=  nil  {
139+ 				return  err 
140+ 			}
141+ 			defer  release ()
109142
110- 			if  versionDeleted  {
111- 				if  pcr .Type  ==  packages_model .TypeCargo  {
112- 					owner , err  :=  user_model .GetUserByID (ctx , pcr .OwnerID )
113- 					if  err  !=  nil  {
114- 						return  fmt .Errorf ("GetUserByID failed: %w" , err )
115- 					}
116- 					if  err  :=  cargo_service .UpdatePackageIndexIfExists (ctx , owner , owner , p .ID ); err  !=  nil  {
117- 						return  fmt .Errorf ("CleanupRule [%d]: cargo.UpdatePackageIndexIfExists failed: %w" , pcr .ID , err )
118- 					}
119- 				}
143+ 			if  err  :=  arch_service .BuildAllRepositoryFiles (ctx , pcr .OwnerID ); err  !=  nil  {
144+ 				return  fmt .Errorf ("CleanupRule [%d]: arch.BuildAllRepositoryFiles failed: %w" , pcr .ID , err )
120145			}
121146		}
147+ 	}
148+ 	return  nil 
149+ }
122150
123- 		if  anyVersionDeleted  {
124- 			switch  pcr .Type  {
125- 			case  packages_model .TypeDebian :
126- 				if  err  :=  debian_service .BuildAllRepositoryFiles (ctx , pcr .OwnerID ); err  !=  nil  {
127- 					return  fmt .Errorf ("CleanupRule [%d]: debian.BuildAllRepositoryFiles failed: %w" , pcr .ID , err )
128- 				}
129- 			case  packages_model .TypeAlpine :
130- 				if  err  :=  alpine_service .BuildAllRepositoryFiles (ctx , pcr .OwnerID ); err  !=  nil  {
131- 					return  fmt .Errorf ("CleanupRule [%d]: alpine.BuildAllRepositoryFiles failed: %w" , pcr .ID , err )
132- 				}
133- 			case  packages_model .TypeRpm :
134- 				if  err  :=  rpm_service .BuildAllRepositoryFiles (ctx , pcr .OwnerID ); err  !=  nil  {
135- 					return  fmt .Errorf ("CleanupRule [%d]: rpm.BuildAllRepositoryFiles failed: %w" , pcr .ID , err )
136- 				}
137- 			case  packages_model .TypeArch :
138- 				release , err  :=  arch_service .AquireRegistryLock (ctx , pcr .OwnerID )
139- 				if  err  !=  nil  {
140- 					return  err 
141- 				}
142- 				defer  release ()
151+ func  ExecuteCleanupRules (ctx  context.Context ) error  {
152+ 	return  packages_model .IterateEnabledCleanupRules (ctx , func (ctx  context.Context , pcr  * packages_model.PackageCleanupRule ) error  {
153+ 		select  {
154+ 		case  <- ctx .Done ():
155+ 			return  db .ErrCancelledf ("While processing package cleanup rules" )
156+ 		default :
157+ 		}
143158
144- 				if  err  :=  arch_service .BuildAllRepositoryFiles (ctx , pcr .OwnerID ); err  !=  nil  {
145- 					return  fmt .Errorf ("CleanupRule [%d]: arch.BuildAllRepositoryFiles failed: %w" , pcr .ID , err )
146- 				}
147- 			}
159+ 		err  :=  executeCleanupOneRule (ctx , pcr )
160+ 		if  err  !=  nil  {
161+ 			log .Error ("CleanupRule [%d]: executeCleanupOneRule failed: %v" , pcr .ID , err )
148162		}
149163		return  nil 
150164	})
151- 	if  err  !=  nil  {
152- 		return  err 
153- 	}
154- 
155- 	return  committer .Commit ()
156165}
157166
158167func  CleanupExpiredData (outerCtx  context.Context , olderThan  time.Duration ) error  {
0 commit comments