annex.maxextensionlength for view
authorJoey Hess <joeyh@joeyh.name>
Fri, 24 Mar 2023 17:53:51 +0000 (13:53 -0400)
committerJoey Hess <joeyh@joeyh.name>
Fri, 24 Mar 2023 18:01:38 +0000 (14:01 -0400)
view: Support annex.maxextensionlength when generating filenames for the
view branch.

Note that refining an existing view will reuse the extension length that was
configured when initially constructing the view. This is necessarily the case
because it reuses the filenames.

Also view files used to have all extensions at the end, no matter how
many there were. Since annex.maxextensionlength's documentation includes
that it's limited to 2 extensions, I made it consistent with that.

Sponsored-by: k0ld on Patreon
Annex/View.hs
Annex/View/ViewedFile.hs
CHANGELOG
Utility/Path.hs
doc/git-annex-view.mdwn
doc/git-annex.mdwn
doc/todo/Configuring_metadata_view_filenames/comment_8_2bcfc677da72637f34904b84fdd95c10._comment [new file with mode: 0644]

index 65db159710a877b7be9ad92da07b205a069479ac..b47e34564b0a026817c35d130f3073455514782f 100644 (file)
@@ -387,7 +387,7 @@ prop_view_roundtrips (AssociatedFile Nothing) _ _ = True
 prop_view_roundtrips (AssociatedFile (Just f)) metadata visible = or
        [ B.null (P.takeFileName f) && B.null (P.takeDirectory f)
        , viewTooLarge view
-       , all hasfields (viewedFiles view viewedFileFromReference (fromRawFilePath f) metadata)
+       , all hasfields (viewedFiles view (viewedFileFromReference' Nothing) (fromRawFilePath f) metadata)
        ]
   where
        view = View (Git.Ref "foo") $
@@ -421,7 +421,9 @@ getViewedFileMetaData = getDirMetaData . dirFromViewedFile . takeFileName
  - branch for the view.
  -}
 applyView :: View -> Maybe Adjustment -> Annex Git.Branch
-applyView = applyView' viewedFileFromReference getWorkTreeMetaData
+applyView v ma = do
+       gc <- Annex.getGitConfig
+       applyView' (viewedFileFromReference gc) getWorkTreeMetaData v ma
 
 {- Generates a new branch for a View, which must be a more narrow
  - version of the View originally used to generate the currently
@@ -553,7 +555,8 @@ updateView view madj = do
                Git.LsTree.LsTreeRecursive
                (Git.LsTree.LsTreeLong True)
                (viewParentBranch view)
-       applyView'' viewedFileFromReference getWorkTreeMetaData view madj l clean $
+       gc <- Annex.getGitConfig
+       applyView'' (viewedFileFromReference gc) getWorkTreeMetaData view madj l clean $
                \ti -> do
                        let ref = Git.Ref.branchFileRef (viewParentBranch view)
                                (getTopFilePath (Git.LsTree.file ti))
index c804a50c0b02eb4aaa8e4728c1c8c0246c715a47..6aa992babb081dcbdb1db66bdad7890b838e9f59 100644 (file)
@@ -1,6 +1,6 @@
 {- filenames (not paths) used in views
  -
- - Copyright 2014 Joey Hess <id@joeyh.name>
+ - Copyright 2014-2023 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -11,6 +11,7 @@ module Annex.View.ViewedFile (
        ViewedFile,
        MkViewedFile,
        viewedFileFromReference,
+       viewedFileFromReference',
        viewedFileReuse,
        dirFromViewedFile,
        prop_viewedFile_roundtrips,
@@ -35,17 +36,27 @@ type MkViewedFile = FilePath -> ViewedFile
  -
  - So, from dir/subdir/file.foo, generate file_%dir%subdir%.foo
  -}
-viewedFileFromReference :: MkViewedFile
-viewedFileFromReference f = concat $
-       [ escape (fromRawFilePath base)
+viewedFileFromReference :: GitConfig -> MkViewedFile
+viewedFileFromReference g = viewedFileFromReference' (annexMaxExtensionLength g)
+
+viewedFileFromReference' :: Maybe Int -> MkViewedFile
+viewedFileFromReference' maxextlen f = concat $
+       [ escape (fromRawFilePath base')
        , if null dirs then "" else "_%" ++ intercalate "%" (map escape dirs) ++ "%"
-       , escape $ fromRawFilePath $ S.concat extensions
+       , escape $ fromRawFilePath $ S.concat extensions'
        ]
   where
        (path, basefile) = splitFileName f
        dirs = filter (/= ".") $ map dropTrailingPathSeparator (splitPath path)
-       (base, extensions) = splitShortExtensions (toRawFilePath basefile')
-       
+       (base, extensions) = case maxextlen of
+               Nothing -> splitShortExtensions (toRawFilePath basefile')
+               Just n -> splitShortExtensions' (n+1) (toRawFilePath basefile')
+       {- Limit to two extensions maximum. -}
+       (base', extensions')
+               | length extensions <= 2 = (base, extensions)
+               | otherwise = 
+                       let (es,more) = splitAt 2 (reverse extensions)
+                       in (base <> mconcat (reverse more), reverse es)
        {- On Windows, if the filename looked like "dir/c:foo" then
         - basefile would look like it contains a drive letter, which will
         - not work. There cannot really be a filename like that, probably,
@@ -90,7 +101,7 @@ prop_viewedFile_roundtrips tf
        -- Relative filenames wanted, not directories.
        | any (isPathSeparator) (end f ++ beginning f) = True
        | isAbsolute f || isDrive f = True
-       | otherwise = dir == dirFromViewedFile (viewedFileFromReference f)
+       | otherwise = dir == dirFromViewedFile (viewedFileFromReference' Nothing f)
   where
        f = fromTestableFilePath tf
        dir = joinPath $ beginning $ splitDirectories f
index 1a2f35bad3b0991f8cd30c11ff1231aad24f34fa..3b7f40eb04d9759973d6888481b0ce4b4e73632b 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,8 @@ git-annex (10.20230322) UNRELEASED; urgency=medium
     drop when annex.adjustedbranchrefresh=1
   * Avoid leaving repo with a detached head when there is a failure
     checking out an updated adjusted branch.
+  * view: Support annex.maxextensionlength when generating filenames for
+    the view branch.
 
  -- Joey Hess <id@joeyh.name>  Thu, 23 Mar 2023 15:04:41 -0400
 
index dcb21400eabc87d35f3c75efe2236aab2ddf0ecc..64ef076ff93730d0dacc2b0aa7fbafd8c4958dcf 100644 (file)
@@ -20,6 +20,7 @@ module Utility.Path (
        runSegmentPaths',
        dotfile,
        splitShortExtensions,
+       splitShortExtensions',
        relPathDirToFileAbs,
        inSearchPath,
        searchPath,
index b8e126403bd5df232e0592ea5f8deb7f18475ec6..f2677019a7392dcf9caa3616163468a01d7da188 100644 (file)
@@ -44,6 +44,12 @@ into the `_` directory and committing will unset the metadata.
 The name of the `_` directory can be changed using the annex.viewunsetdirectory
 git config.
 
+Filenames in the view branch include their path within the original branch, to
+ensure that they are unique. The path comes after the main filename, and
+before any extensions. For example, "foo/bar.baz" will have a name
+like "bar_%foo%.baz". annex.maxextensionlength can be used to configure
+what is treated as an extension.
+
 # OPTIONS
 
 * The [[git-annex-common-options]](1) can be used.
index 5e63631be7ef82bd85a8697af42904d779e1e82c..aac408d3ff9f9d55c314bd0d5d98cdd21192a115 100644 (file)
@@ -825,9 +825,11 @@ repository, using [[git-annex-config]]. See its man page for a list.)
 
 * `annex.maxextensionlength`
 
-  Maximum length, in bytes, of what is considered a filename extension when
-  adding a file to a backend that preserves filename extensions. The
-  default length is 4, which allows extensions like "jpeg". The dot before
+  Maximum length, in bytes, of what is considered a filename extension.
+  This is used when adding a file to a backend that preserves filename extensions,
+  and also when generating a view branch.
+
+  The default length is 4, which allows extensions like "jpeg". The dot before
   the extension is not counted part of its length. At most two extensions
   at the end of a filename will be preserved, e.g. .gz or .tar.gz .
 
diff --git a/doc/todo/Configuring_metadata_view_filenames/comment_8_2bcfc677da72637f34904b84fdd95c10._comment b/doc/todo/Configuring_metadata_view_filenames/comment_8_2bcfc677da72637f34904b84fdd95c10._comment
new file mode 100644 (file)
index 0000000..b379529
--- /dev/null
@@ -0,0 +1,9 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 8"""
+ date="2023-03-24T17:48:43Z"
+ content="""
+I've made git-annex view use `annex.maxextensionlength`. Note that refining
+an existing view will reuse the extension length that was configured when
+initially constructing the view.
+"""]]