summaryrefslogtreecommitdiff
path: root/Command/Unannex.hs
blob: fbeaffa52aa6397327e50fe5f64b339ae3a2fe11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
{- git-annex command
 -
 - Copyright 2010-2013 Joey Hess <joey@kitenet.net>
 -
 - Licensed under the GNU GPL version 3 or higher.
 -}

{-# LANGUAGE CPP #-}

module Command.Unannex where

import Common.Annex
import Command
import Config
import qualified Annex
import Logs.Location
import Annex.Content
import Annex.Content.Direct
import qualified Git.Command
import qualified Git.LsFiles as LsFiles

def :: [Command]
def = [command "unannex" paramPaths seek SectionUtility
		"undo accidential add command"]

seek :: [CommandSeek]
seek = [withFilesInGit $ whenAnnexed start]

start :: FilePath -> (Key, Backend) -> CommandStart
start file (key, _) = stopUnless (inAnnex key) $ do
	showStart "unannex" file
	next $ ifM isDirect
		( performDirect file key
		, performIndirect file key)

performIndirect :: FilePath -> Key -> CommandPerform
performIndirect file key = do
	liftIO $ removeFile file
	
	-- git rm deletes empty directory without --cached
	inRepo $ Git.Command.run [Params "rm --cached --force --quiet --", File file]
	
	-- If the file was already committed, it is now staged for removal.
	-- Commit that removal now, to avoid later confusing the
	-- pre-commit hook, if this file is later added back to
	-- git as a normal non-annexed file, to thinking that the
	-- file has been unlocked and needs to be re-annexed.
	(s, reap) <- inRepo $ LsFiles.staged [file]
	when (not $ null s) $
		inRepo $ Git.Command.run
			[ Param "commit"
			, Param "-q"
			, Param "--no-verify"
			, Param "-m", Param "content removed from git annex"
			, Param "--", File file
			]
	void $ liftIO reap

	next $ cleanupIndirect file key

cleanupIndirect :: FilePath -> Key -> CommandCleanup
cleanupIndirect file key = do
	ifM (Annex.getState Annex.fast)
		( goFast
		, go
		)
	return True
  where
#ifdef mingw32_HOST_OS
	goFast = go
#else
	goFast = do
		-- fast mode: hard link to content in annex
		src <- calcRepo $ gitAnnexLocation key
		-- creating a hard link could fall; fall back to non fast mode
		ifM (liftIO $ catchBoolIO $ createLink src file >> return True)
			( thawContent file
			, go
			)
#endif
	go = do
		fromAnnex key file
		logStatus key InfoMissing


performDirect :: FilePath -> Key -> CommandPerform
performDirect file key = do
	-- --force is needed when the file is not committed
	inRepo $ Git.Command.run [Params "rm --cached --force --quiet --", File file]
	next $ cleanupDirect file key

{- The direct mode file is not touched during unannex, so the content
 - is already where it needs to be, so this does not need to do anything
 - except remove it from the associated file map (which also updates
 - the location log if this was the last copy), and, if this was the last
 - associated file, remove the inode cache. -}
cleanupDirect :: FilePath -> Key -> CommandCleanup
cleanupDirect file key = do
	fs <- removeAssociatedFile key file
	when (null fs) $
		removeInodeCache key
	return True