@@ -32,7 +32,7 @@ import Distribution.PackageDescription
32
32
import Distribution.PackageDescription.Configuration
33
33
import Distribution.License
34
34
35
- import Data.Maybe (fromMaybe )
35
+ import Data.Maybe (fromMaybe , fromJust )
36
36
import Data.Set (Set )
37
37
import qualified Data.Set as Set
38
38
import Data.Map (Map )
@@ -50,6 +50,7 @@ data TagsFeature = TagsFeature {
50
50
queryGetTagList :: forall m . MonadIO m => m [(Tag , Set PackageName )],
51
51
queryTagsForPackage :: forall m . MonadIO m => PackageName -> m (Set Tag ),
52
52
queryReviewTagsForPackage :: forall m . MonadIO m => PackageName -> m (Maybe (Set Tag ,Set Tag )),
53
+ queryAliasForTag :: MonadIO m => Tag -> m (Maybe Tag ),
53
54
54
55
-- All package names that were modified, and all tags that were modified
55
56
-- In almost all cases, one of these will be a singleton. Happstack
@@ -68,7 +69,8 @@ data TagsFeature = TagsFeature {
68
69
withTagPath :: forall a . DynamicPath -> (Tag -> Set PackageName -> ServerPartE a ) -> ServerPartE a ,
69
70
collectTags :: forall m . MonadIO m => Set PackageName -> m (Map PackageName (Set Tag )),
70
71
71
- putTags :: PackageName -> ServerPartE ()
72
+ putTags :: PackageName -> ServerPartE () ,
73
+ mergeTags :: Tag -> ServerPartE ()
72
74
73
75
}
74
76
@@ -80,6 +82,8 @@ data TagsResource = TagsResource {
80
82
tagListing :: Resource ,
81
83
packageTagsListing :: Resource ,
82
84
packageTagsEdit :: Resource ,
85
+ tagAliasEdit :: Resource ,
86
+ tagAliasEditForm :: Resource ,
83
87
84
88
tagUri :: String -> Tag -> String ,
85
89
tagsUri :: String -> String ,
@@ -93,20 +97,23 @@ initTagsFeature :: ServerEnv
93
97
initTagsFeature ServerEnv {serverStateDir} = do
94
98
tagsState <- tagsStateComponent serverStateDir
95
99
tagsReview <- tagsReviewComponent serverStateDir
100
+ tagAlias <- tagsAliasComponent serverStateDir
96
101
specials <- newMemStateWHNF emptyPackageTags
97
102
updateTag <- newHook
98
103
99
104
return $ \ core@ CoreFeature {.. } upload -> do
100
- let feature = tagsFeature core upload tagsState tagsReview specials updateTag
105
+ let feature = tagsFeature core upload tagsState tagsReview tagAlias specials updateTag
101
106
102
107
registerHookJust packageChangeHook isPackageChangeAny $ \ (pkgid, mpkginfo) ->
103
108
case mpkginfo of
104
109
Nothing -> return ()
105
110
Just pkginfo -> do
106
111
let pkgname = packageName pkgid
107
- tags = Set. fromList . constructImmutableTags . pkgDesc $ pkginfo
108
- updateState tagsState . SetPackageTags pkgname $ tags
109
- runHook_ updateTag (Set. singleton pkgname, tags)
112
+ tags = constructImmutableTags . pkgDesc $ pkginfo
113
+ aliases <- sequence $ map (\ tag -> queryState tagAlias $ GetTagAlias tag) tags
114
+ let newtags = Set. fromList $ map fromJust aliases
115
+ updateState tagsState . SetPackageTags pkgname $ newtags
116
+ runHook_ updateTag (Set. singleton pkgname, newtags)
110
117
111
118
return feature
112
119
@@ -123,6 +130,20 @@ tagsStateComponent stateDir = do
123
130
, resetState = tagsStateComponent
124
131
}
125
132
133
+ tagsAliasComponent :: FilePath -> IO (StateComponent AcidState TagAlias )
134
+ tagsAliasComponent stateDir = do
135
+ st <- openLocalStateFrom (stateDir </> " db" </> " Tags" </> " Alias" ) emptyTagAlias
136
+ return StateComponent {
137
+ stateDesc = " Tags Alias"
138
+ , stateHandle = st
139
+ , getState = query st GetTagAliasesState
140
+ , putState = update st . AddTagAliasesState
141
+ -- , backupState = \_ pkgTags -> [csvToBackup ["tags.csv"] $ tagsToCSV pkgTags]
142
+ -- , restoreState = tagsBackup
143
+ -- , resetState = tagsStateComponent
144
+ }
145
+
146
+
126
147
tagsReviewComponent :: FilePath -> IO (StateComponent AcidState ReviewTags )
127
148
tagsReviewComponent stateDir = do
128
149
st <- openLocalStateFrom (stateDir </> " db" </> " Tags" </> " Review" ) emptyReviewTags
@@ -142,6 +163,7 @@ tagsFeature :: CoreFeature
142
163
-> UploadFeature
143
164
-> StateComponent AcidState PackageTags
144
165
-> StateComponent AcidState ReviewTags
166
+ -> StateComponent AcidState TagAlias
145
167
-> MemState PackageTags
146
168
-> Hook (Set PackageName , Set Tag ) ()
147
169
-> TagsFeature
@@ -152,13 +174,16 @@ tagsFeature CoreFeature{ queryGetPackageIndex
152
174
UploadFeature { guardAuthorisedAsUploaderOrMaintainerOrTrustee }
153
175
tagsState
154
176
tagsReview
177
+ tagsAlias
155
178
calculatedTags
156
179
tagsUpdated
157
180
= TagsFeature {.. }
158
181
where
159
182
tagsResource = fix $ \ r -> TagsResource
160
183
{ tagsListing = resourceAt " /packages/tags/.:format"
161
184
, tagListing = resourceAt " /packages/tag/:tag.:format"
185
+ , tagAliasEdit = resourceAt " /packages/tag/:tag/alias"
186
+ , tagAliasEditForm = resourceAt " /packages/tag/:tag/alias/edit"
162
187
, packageTagsListing = resourceAt " /package/:package/tags.:format"
163
188
, packageTagsEdit = resourceAt " /package/:package/tags/edit"
164
189
, tagUri = \ format tag -> renderResource (tagListing r) [display tag, format]
@@ -200,6 +225,9 @@ tagsFeature CoreFeature{ queryGetPackageIndex
200
225
queryTagsForPackage :: MonadIO m => PackageName -> m (Set Tag )
201
226
queryTagsForPackage pkgname = queryState tagsState (TagsForPackage pkgname)
202
227
228
+ queryAliasForTag :: MonadIO m => Tag -> m (Maybe Tag )
229
+ queryAliasForTag tag = queryState tagsAlias (GetTagAlias tag)
230
+
203
231
queryReviewTagsForPackage :: MonadIO m => PackageName -> m (Maybe (Set Tag ,Set Tag ))
204
232
queryReviewTagsForPackage pkgname = queryState tagsReview (LookupReviewTags pkgname)
205
233
@@ -221,6 +249,29 @@ tagsFeature CoreFeature{ queryGetPackageIndex
221
249
pkgMap <- liftM packageTags $ queryState tagsState GetPackageTags
222
250
return $ Map. fromDistinctAscList . map (\ pkg -> (pkg, Map. findWithDefault Set. empty pkg pkgMap)) $ Set. toList pkgs
223
251
252
+
253
+ mergeTags :: Tag -> ServerPartE ()
254
+ mergeTags deprTag = do
255
+ tags <- optional $ look " tags"
256
+ index <- queryGetPackageIndex
257
+ case simpleParse =<< tags of
258
+ Just (Tag orig) -> do
259
+ void $ updateState tagsAlias $ AddTagAlias (Tag orig) deprTag
260
+ void $ constructMergedTagIndex (Tag orig) deprTag index
261
+ _ -> errBadRequest " Tag not recognised" [MText " Couldn't parse tag. It should be a single tag." ]
262
+
263
+ -- tags on merging
264
+ constructMergedTagIndex :: forall m . MonadIO m => Tag -> Tag -> PackageIndex PkgInfo -> m (PackageTags )
265
+ constructMergedTagIndex orig depr = foldM addToTags emptyPackageTags . PackageIndex. allPackagesByName
266
+ where addToTags calcTags pkgList = do
267
+ let info = pkgDesc $ last pkgList
268
+ ! pn = packageName info
269
+ pkgTags <- queryTagsForPackage pn
270
+ let newTags = if (depr `elem` pkgTags) then (Set. delete depr (Set. insert orig pkgTags)) else pkgTags
271
+ void $ updateState tagsState $ SetPackageTags pn newTags
272
+ runHook_ tagsUpdated (Set. singleton pn, newTags)
273
+ return (setTags pn newTags calcTags)
274
+
224
275
putTags :: PackageName -> ServerPartE ()
225
276
putTags pkgname = do
226
277
guardValidPackageName pkgname
@@ -235,16 +286,20 @@ tagsFeature CoreFeature{ queryGetPackageIndex
235
286
user <- guardAuthorisedAsUploaderOrMaintainerOrTrustee pkgname
236
287
case user of
237
288
" Uploaders" -> do
289
+ aliases <- sequence $ map (\ tag -> queryState tagsAlias $ GetTagAlias tag) add
238
290
calcTags <- queryTagsForPackage pkgname
239
- let addTags = Set. fromList add `Set.difference` calcTags
291
+ let add_ = map fromJust aliases
292
+ addTags = Set. fromList add_ `Set.difference` calcTags
240
293
delTags = Set. fromList del `Set.intersection` calcTags
241
294
void $ updateState tagsReview $ InsertReviewTags pkgname addTags delTags
242
295
return ()
243
296
_ -> do
244
297
calcTags <- queryTagsForPackage pkgname
298
+ aliases <- sequence $ map (\ tag -> queryState tagsAlias $ GetTagAlias tag) add
245
299
revTags <- queryReviewTagsForPackage pkgname
246
300
let tagSet = (addTags `Set.union` calcTags) `Set.difference` delTags
247
- addTags = Set. fromList add
301
+ add_ = map fromJust aliases
302
+ addTags = Set. fromList add_
248
303
delTags = Set. fromList del
249
304
rdel = case simpleParse =<< rdelns of
250
305
Just (TagList rdel) -> rdel
@@ -282,6 +337,8 @@ constructImmutableTagIndex = foldl' addToTags emptyPackageTags . PackageIndex.al
282
337
! tags = constructImmutableTags info
283
338
in setTags pn (Set. fromList tags) calcTags
284
339
340
+
341
+
285
342
-- These are constructed when a package is uploaded/on startup
286
343
constructCategoryTags :: PackageDescription -> [Tag ]
287
344
constructCategoryTags = map (tagify . map toLower) . fillMe . categorySplit . category
0 commit comments