git-annex/Command/AddUrl.hs

141 lines
4.1 KiB
Haskell
Raw Normal View History

2011-07-01 21:15:46 +00:00
{- git-annex command
-
- Copyright 2011 Joey Hess <joey@kitenet.net>
-
- Licensed under the GNU GPL version 3 or higher.
-}
module Command.AddUrl where
import Network.URI
2011-10-05 20:02:51 +00:00
import Common.Annex
2011-07-01 21:15:46 +00:00
import Command
import Backend
2011-07-01 21:15:46 +00:00
import qualified Command.Add
import qualified Annex
import qualified Annex.Queue
import qualified Backend.URL
import qualified Utility.Url as Url
2011-10-04 04:40:47 +00:00
import Annex.Content
import Logs.Web
import qualified Option
import Types.Key
import Types.KeySource
import Config
2013-01-06 21:34:44 +00:00
import Annex.Content.Direct
import Logs.Location
2011-07-01 21:15:46 +00:00
def :: [Command]
2013-03-11 23:55:01 +00:00
def = [notBareRepo $ withOptions [fileOption, pathdepthOption, relaxedOption] $
command "addurl" (paramRepeating paramUrl) seek
SectionCommon "add urls to annex"]
fileOption :: Option
fileOption = Option.field [] "file" paramFile "specify what file the url is added to"
2011-07-01 21:15:46 +00:00
2012-02-16 16:25:19 +00:00
pathdepthOption :: Option
2012-02-16 16:37:30 +00:00
pathdepthOption = Option.field [] "pathdepth" paramNumber "path components to use in filename"
2012-02-16 16:25:19 +00:00
2013-03-11 23:55:01 +00:00
relaxedOption :: Option
relaxedOption = Option.flag [] "relaxed" "skip size check"
2011-07-01 21:15:46 +00:00
seek :: [CommandSeek]
seek = [withField fileOption return $ \f ->
2013-03-11 23:55:01 +00:00
withFlag relaxedOption $ \relaxed ->
2012-02-16 16:25:19 +00:00
withField pathdepthOption (return . maybe Nothing readish) $ \d ->
2013-03-11 23:55:01 +00:00
withStrings $ start relaxed f d]
2011-07-01 21:15:46 +00:00
2013-03-11 23:55:01 +00:00
start :: Bool -> Maybe FilePath -> Maybe Int -> String -> CommandStart
start relaxed optfile pathdepth s = go $ fromMaybe bad $ parseURI s
2012-11-12 05:05:04 +00:00
where
bad = fromMaybe (error $ "bad url " ++ s) $
parseURI $ escapeURIString isUnescapedInURI s
go url = do
let file = fromMaybe (url2file url pathdepth) optfile
showStart "addurl" file
2013-03-11 23:55:01 +00:00
next $ perform relaxed s file
2011-10-31 20:46:51 +00:00
2013-03-11 23:55:01 +00:00
perform :: Bool -> String -> FilePath -> CommandPerform
perform relaxed url file = ifAnnexed file addurl geturl
2012-11-12 05:05:04 +00:00
where
geturl = do
liftIO $ createDirectoryIfMissing True (parentDir file)
2013-03-11 23:55:01 +00:00
ifM (Annex.getState Annex.fast <||> pure relaxed)
( nodownload relaxed url file , download url file )
2013-03-12 19:58:36 +00:00
addurl (key, _backend)
| relaxed = do
setUrlPresent key url
next $ return True
| otherwise = do
headers <- getHttpHeaders
ifM (liftIO $ Url.check url headers $ keySize key)
( do
setUrlPresent key url
next $ return True
, do
warning $ "failed to verify url: " ++ url
stop
)
download :: String -> FilePath -> CommandPerform
download url file = do
showAction $ "downloading " ++ url ++ " "
let dummykey = Backend.URL.fromUrl url Nothing
tmp <- fromRepo $ gitAnnexTmpLocation dummykey
liftIO $ createDirectoryIfMissing True (parentDir tmp)
stopUnless (downloadUrl [url] tmp) $ do
backend <- chooseBackend file
let source = KeySource
{ keyFilename = file
, contentLocation = tmp
, inodeCache = Nothing
}
k <- genKey source backend
case k of
Nothing -> stop
Just (key, _) -> next $ cleanup url file key (Just tmp)
cleanup :: String -> FilePath -> Key -> Maybe FilePath -> CommandCleanup
cleanup url file key mtmp = do
when (isJust mtmp) $
logStatus key InfoPresent
setUrlPresent key url
Command.Add.addLink file key False
whenM isDirect $ do
void $ addAssociatedFile key file
{- For moveAnnex to work in direct mode, the symlink
- must already exist, so flush the queue. -}
Annex.Queue.flush
maybe noop (moveAnnex key) mtmp
return True
2011-07-01 21:15:46 +00:00
2013-03-11 23:55:01 +00:00
nodownload :: Bool -> String -> FilePath -> CommandPerform
nodownload relaxed url file = do
headers <- getHttpHeaders
2013-03-11 23:55:01 +00:00
(exists, size) <- if relaxed
then pure (True, Nothing)
else liftIO $ Url.exists url headers
if exists
then do
let key = Backend.URL.fromUrl url size
next $ cleanup url file key Nothing
else do
warning $ "unable to access url: " ++ url
stop
2012-02-16 16:25:19 +00:00
url2file :: URI -> Maybe Int -> FilePath
url2file url pathdepth = case pathdepth of
Nothing -> filesize $ escape fullurl
Just depth
| depth > 0 -> frombits $ drop depth
2012-02-16 18:28:17 +00:00
| depth < 0 -> frombits $ reverse . take (negate depth) . reverse
| otherwise -> error "bad --pathdepth"
2012-11-12 05:05:04 +00:00
where
fullurl = uriRegName auth ++ uriPath url ++ uriQuery url
frombits a = join "/" $ a urlbits
urlbits = map (filesize . escape) $ filter (not . null) $ split "/" fullurl
auth = fromMaybe (error $ "bad url " ++ show url) $ uriAuthority url
filesize = take 255
escape = replace "/" "_" . replace "?" "_"