cc32e31161
An adjusted view branch has a name like "refs/heads/adjusted/views/master(author=_)(unlocked)", so it is a view branch that has been converted to an adjusted branch. Made Logs.View support such branch names. So now git-annex sync and pre-commit handle updating metadata on commit in such a branch. Much remains to be done to fully support adjusted view branches, including actually applying the adjustment when updating the view branch. Sponsored-by: Graham Spencer on Patreon
160 lines
4.7 KiB
Haskell
160 lines
4.7 KiB
Haskell
{- git-annex recent views log
|
|
-
|
|
- The most recently accessed view comes first.
|
|
-
|
|
- This file is stored locally in .git/annex/, not in the git-annex branch.
|
|
-
|
|
- Copyright 2014-2023 Joey Hess <id@joeyh.name>
|
|
-
|
|
- Licensed under the GNU AGPL version 3 or higher.
|
|
-}
|
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
module Logs.View (
|
|
currentView,
|
|
setView,
|
|
removeView,
|
|
recentViews,
|
|
branchView,
|
|
fromViewBranch,
|
|
is_branchView,
|
|
branchViewPrefix,
|
|
prop_branchView_legal,
|
|
) where
|
|
|
|
import Annex.Common
|
|
import Types.View
|
|
import Types.MetaData
|
|
import Types.AdjustedBranch
|
|
import Annex.AdjustedBranch.Name
|
|
import qualified Git
|
|
import qualified Git.Branch
|
|
import qualified Git.Ref
|
|
import Git.Types
|
|
import Logs.File
|
|
|
|
import qualified Data.Text as T
|
|
import qualified Data.Set as S
|
|
import Data.Char
|
|
import qualified Data.ByteString as B
|
|
|
|
setView :: View -> Annex ()
|
|
setView v = do
|
|
old <- take 99 . filter (/= v) <$> recentViews
|
|
writeViews (v : old)
|
|
|
|
writeViews :: [View] -> Annex ()
|
|
writeViews l = do
|
|
f <- fromRepo gitAnnexViewLog
|
|
writeLogFile f $ unlines $ map show l
|
|
|
|
removeView :: View -> Annex ()
|
|
removeView v = writeViews =<< filter (/= v) <$> recentViews
|
|
|
|
recentViews :: Annex [View]
|
|
recentViews = do
|
|
f <- fromRawFilePath <$> fromRepo gitAnnexViewLog
|
|
liftIO $ mapMaybe readish . lines <$> catchDefaultIO [] (readFile f)
|
|
|
|
{- Gets the currently checked out view, if there is one.
|
|
-
|
|
- The view may also have an adjustment applied to it.
|
|
-}
|
|
currentView :: Annex (Maybe (View, Maybe Adjustment))
|
|
currentView = go =<< inRepo Git.Branch.current
|
|
where
|
|
go (Just b) = case adjustedToOriginal b of
|
|
Nothing -> getvb b Nothing
|
|
Just (adj, b') -> getvb b' (Just adj)
|
|
go Nothing = return Nothing
|
|
|
|
getvb b madj
|
|
| branchViewPrefix `B.isPrefixOf` fromRef' b = do
|
|
vb <- headMaybe
|
|
. filter (\v -> branchView v Nothing == b || branchViewOld v == b)
|
|
<$> recentViews
|
|
case vb of
|
|
Just vb' -> return (Just (vb', madj))
|
|
Nothing -> return Nothing
|
|
| otherwise = return Nothing
|
|
|
|
{- Note that this is not the prefix used when an adjustment is applied to a
|
|
- view branch. -}
|
|
branchViewPrefix :: B.ByteString
|
|
branchViewPrefix = "refs/heads/views"
|
|
|
|
{- Generates a git branch name for a View, which may also have an
|
|
- adjustment applied to it.
|
|
-
|
|
- There is no guarantee that each view gets a unique branch name,
|
|
- but the branch name is used to express the view as well as possible
|
|
- given the constraints on git branch names. It includes the name of the
|
|
- parent branch, and what metadata is used.
|
|
-}
|
|
branchView :: View -> Maybe Adjustment -> Git.Branch
|
|
branchView view madj = case madj of
|
|
Nothing -> vb
|
|
Just adj -> adjBranch $ originalToAdjusted vb adj
|
|
where
|
|
basebranch = fromRef' (Git.Ref.base (viewParentBranch view))
|
|
vb = Git.Ref $ branchViewPrefix <> "/" <> basebranch
|
|
<> "(" <> branchViewDesc view False <> ")"
|
|
|
|
{- Old name used for a view did not include the name of the parent branch. -}
|
|
branchViewOld :: View -> Git.Branch
|
|
branchViewOld view = Git.Ref $
|
|
branchViewPrefix <> "/" <> branchViewDesc view True
|
|
|
|
branchViewDesc :: View -> Bool -> B.ByteString
|
|
branchViewDesc view pareninvisibles = encodeBS $
|
|
intercalate ";" $ map branchcomp (viewComponents view)
|
|
where
|
|
branchcomp c
|
|
| viewVisible c || not pareninvisibles = branchcomp' c
|
|
| otherwise = "(" ++ branchcomp' c ++ ")"
|
|
branchcomp' (ViewComponent metafield viewfilter _) = concat
|
|
[ forcelegal (T.unpack (fromMetaField metafield))
|
|
, branchvals viewfilter
|
|
]
|
|
branchvals (FilterValues set) = '=' : branchset set
|
|
branchvals (FilterGlob glob) = '=' : forcelegal glob
|
|
branchvals (ExcludeValues set) = "!=" ++ branchset set
|
|
branchvals (FilterValuesOrUnset set _) = '=' : branchset set
|
|
branchvals (FilterGlobOrUnset glob _) = '=' : forcelegal glob
|
|
branchset = intercalate ","
|
|
. map (forcelegal . decodeBS . fromMetaValue)
|
|
. S.toList
|
|
forcelegal s
|
|
| Git.Ref.legal True s = s
|
|
| otherwise = map (\c -> if isAlphaNum c then c else '_') s
|
|
|
|
is_branchView :: Git.Branch -> Bool
|
|
is_branchView b = case adjustedToOriginal b of
|
|
Nothing -> hasprefix b
|
|
Just (_adj, b') -> hasprefix b'
|
|
where
|
|
hasprefix (Ref b') = (branchViewPrefix <> "/") `B.isPrefixOf` b'
|
|
|
|
{- Converts a view branch as generated by branchView (but not by
|
|
- branchViewOld) back to the parent branch.
|
|
- Has no effect on other branches. -}
|
|
fromViewBranch :: Git.Branch -> Git.Branch
|
|
fromViewBranch b = case adjustedToOriginal b of
|
|
Nothing -> go b
|
|
Just (_adj, b') -> go b'
|
|
where
|
|
go b' =
|
|
let bs = fromRef' b'
|
|
in if (branchViewPrefix <> "/") `B.isPrefixOf` bs
|
|
then
|
|
let (branch, _desc) = separate' (== openparen) (B.drop prefixlen bs)
|
|
in Ref branch
|
|
else b'
|
|
|
|
prefixlen = B.length branchViewPrefix + 1
|
|
openparen = fromIntegral (ord '(')
|
|
|
|
prop_branchView_legal :: View -> Bool
|
|
prop_branchView_legal = Git.Ref.legal False
|
|
. fromRef . (\v -> branchView v Nothing)
|