git-annex 4.20130521.2 → 4.20130601
raw patch · 259 files changed
+5323/−683 lines, 259 filesbinary-added
Files
- Annex.hs +3/−7
- Annex/Branch.hs +1/−1
- Annex/CatFile.hs +24/−3
- Annex/Content.hs +2/−3
- Annex/Content/Direct.hs +1/−1
- Annex/Direct.hs +23/−17
- Annex/Exception.hs +2/−3
- Annex/FileMatcher.hs +4/−3
- Annex/Journal.hs +1/−1
- Annex/ReplaceFile.hs +15/−10
- Assistant.hs +6/−113
- Assistant/Install/AutoStart.o binary
- Assistant/Install/Menu.o binary
- Assistant/NetMessager.hs +105/−61
- Assistant/Sync.hs +7/−2
- Assistant/Threads/Watcher.hs +0/−1
- Assistant/Threads/XMPPClient.hs +49/−21
- Assistant/Threads/XMPPPusher.hs +81/−0
- Assistant/Types/NetMessager.hs +30/−17
- Assistant/WebApp/Configurators/XMPP.hs +27/−23
- Assistant/XMPP.hs +25/−5
- Assistant/XMPP/Client.hs +18/−11
- Assistant/XMPP/Git.hs +125/−71
- Build/Configure.o binary
- Build/DesktopFile.o binary
- Build/InstallDesktopFile.o binary
- Build/TestConfig.o binary
- CHANGELOG +28/−0
- Command/Content.hs +48/−0
- Command/FuzzTest.hs +288/−0
- Command/Group.hs +1/−1
- Command/Status.hs +2/−1
- Command/Sync.hs +11/−10
- Command/Vicfg.hs +10/−6
- Command/WebApp.hs +29/−15
- Config/Files.o binary
- Git/Branch.hs +2/−1
- Git/CatFile.hs +1/−1
- Git/CheckAttr.hs +1/−1
- Git/Command.hs +4/−2
- Git/DiffTree.hs +4/−1
- Git/HashObject.hs +1/−1
- Git/Ref.hs +20/−9
- Git/Types.hs +1/−1
- GitAnnex.hs +4/−4
- Limit.hs +20/−17
- Locations.hs +5/−0
- Logs/Transfer.hs +1/−1
- Remote/Git.hs +25/−17
- Remote/Hook.hs +31/−21
- Seek.hs +2/−1
- Setup.o binary
- Test.hs +39/−1
- Types/FileMatcher.hs +13/−0
- Usage.hs +2/−0
- Utility/CoProcess.hs +60/−17
- Utility/Daemon.hs +1/−1
- Utility/Directory.o binary
- Utility/Env.o binary
- Utility/Exception.o binary
- Utility/ExternalSHA.o binary
- Utility/FileSystemEncoding.o binary
- Utility/FreeDesktop.o binary
- Utility/Matcher.hs +76/−18
- Utility/Misc.o binary
- Utility/Monad.o binary
- Utility/Path.o binary
- Utility/Process.o binary
- Utility/SRV.hs +1/−2
- Utility/SafeCommand.o binary
- Utility/TList.hs +11/−4
- Utility/ThreadScheduler.hs +8/−5
- Utility/Tmp.o binary
- Utility/Url.hs +14/−20
- Utility/UserInfo.o binary
- Utility/WebApp.hs +1/−0
- debian/changelog +28/−0
- doc/Android.mdwn +0/−7
- doc/Android/comment_10_20e3d513b8b97496d76aca4619026cd6._comment +16/−0
- doc/Android/comment_11_c96b8f1cc1583a74eb2483f48357f023._comment +15/−0
- doc/Android/comment_12_6551f5fa081494b079c10a33c9b0d8ad._comment +10/−0
- doc/Android/comment_13_7c633d245651ec08f63194fe1fc194ae._comment +8/−0
- doc/Android/comment_14_60c2403140085f9caf48a33b59a36ab4._comment +8/−0
- doc/Android/comment_15_77bafc01b47d4cf8f96bde2b6704ed71._comment +8/−0
- doc/Android/comment_16_9af73451be09f03cfff81fdf9481ffc4._comment +27/−0
- doc/Android/comment_17_f76561a654b534df3a807b1c045710b2._comment +8/−0
- doc/Android/comment_18_1b46cdf154ddadfe17e4b6e4054dc619._comment +17/−0
- doc/Android/comment_7_a56628a622da752806c42c5b8b54ceef._comment +8/−0
- doc/Android/comment_8_19656ec99b8f6aa64c1d01a3c9ae9bd0._comment +8/−0
- doc/Android/comment_9_55e703ae105d0c0ee9ac50df8cc59dfb._comment +10/−0
- doc/assistant/release_notes.mdwn +9/−4
- doc/bugs/3.20121113_build_error___39__not_in_scope_getAddBoxComR__39__.mdwn +33/−0
- doc/bugs/Android_app_permission_denial_on_startup.mdwn +2/−0
- doc/bugs/Assistant_doesn__39__t_actually_sync_file_contents_by_default.mdwn +16/−0
- doc/bugs/Cabal_cannot_solve_dependencies.mdwn +36/−0
- doc/bugs/Difficult_to_troubleshoot_XMPP_login_failures.mdwn +11/−0
- doc/bugs/Direct_mode_repositories_end_up_with_unstaged_changes.mdwn +46/−0
- doc/bugs/Direct_mode_repositories_still_use_symlinks_sometimes.mdwn +32/−0
- doc/bugs/Glacier_remote_uploads_duplicates.mdwn +31/−0
- doc/bugs/Hard_links_not_synced_in_direct_mode.mdwn +125/−0
- doc/bugs/Huge_annex_out_of_memory_on_switch_to_indirect_mode_and_status.mdwn +61/−0
- doc/bugs/Is_there_any_way_to_rate_limit_uploads_to_an_S3_backend__63__.mdwn +19/−0
- doc/bugs/Killing_the_assistant_daemon_leaves_ssh_mux_sessions_behind.mdwn +38/−0
- doc/bugs/Lost_S3_Remote/comment_1_6e80e6db6671581d471fc9a54181c04c._comment +10/−0
- doc/bugs/Lost_S3_Remote/comment_2_c99c65882a3924f4890e500f9492b442._comment +8/−0
- doc/bugs/Lost_S3_Remote/comment_3_1e434d5a20a692cd9dc7f6f8f20f30dd._comment +8/−0
- doc/bugs/Manual_content_mode_isn__39__t_manual.mdwn +89/−0
- doc/bugs/Manual_mode_weirdness.mdwn +37/−0
- doc/bugs/More_sync__39__ing_weirdness_with_the_assistant_branch_on_OSX.mdwn +15/−0
- doc/bugs/OSX_app_issues/comment_10_54d8f3e429df9a9958370635c890abf0._comment +11/−0
- doc/bugs/OSX_app_issues/comment_10_6d23232fbb15d0ee3ab532a4884f81ed._comment +10/−0
- doc/bugs/OSX_app_issues/comment_11_5db2baa771fd01a284eac8a16c1c8c67._comment +8/−0
- doc/bugs/OSX_app_issues/comment_11_bb2ceb95a844449795addee6986d0763._comment +26/−0
- doc/bugs/OSX_app_issues/comment_12_62170597c7f441d84d48986857998858._comment +10/−0
- doc/bugs/OSX_app_issues/comment_12_f3bc5a4e4895ac9351786f0bdd8005ba._comment +11/−0
- doc/bugs/OSX_app_issues/comment_2_fd560811c57df5cbc3976639642b8b19._comment +8/−0
- doc/bugs/OSX_app_issues/comment_7_93e0bb53ac2d7daef53426fbdc5f92d9._comment +15/−0
- doc/bugs/OSX_app_issues/comment_8_141eac2f3fb25fe18b4268786f00ad6a._comment +8/−0
- doc/bugs/OSX_app_issues/comment_8_f4d5b2645d7f29b80925159efb94a998._comment +8/−0
- doc/bugs/OSX_app_issues/comment_9_2e6dfca0fd8df04066769653724eae28._comment +17/−0
- doc/bugs/OSX_app_issues/comment_9_e1bbe83a1b9a7385ed6d443d0cc22bc7._comment +18/−0
- doc/bugs/Problems_building_on_Mac_OS_X.mdwn +62/−0
- doc/bugs/Rsync_encrypted_remote_asks_for_ssh_key_password_for_each_file.mdwn +30/−0
- doc/bugs/Switching_from_indirect_mode_to_direct_mode_breaks_duplicates.mdwn +30/−0
- doc/bugs/__34__fatal:_bad_config_file__34__.mdwn +14/−0
- doc/bugs/adding_an_rsync.net_repo_give_an_gpg_error.mdwn +2/−0
- doc/bugs/assistant_doesn__39__t_sync_empty_directories.mdwn +30/−0
- doc/bugs/assistant_doesn__39__t_sync_file_permissions.mdwn +45/−0
- doc/bugs/creating_a_plain_directory_where_a_mountpoint_should_have_been.mdwn +27/−0
- doc/bugs/git-annex_has_issues_with_git_when_staging__47__commiting_logs.mdwn +34/−0
- doc/bugs/git-annex_on_crippled_filesystem_can_still_failed_due_to_case_.mdwn +32/−0
- doc/bugs/git_annex_gets_confused_about_remotes_with_dots_in_their_names.mdwn +34/−0
- doc/bugs/git_annex_sync_in_direct_mode_does_not_honor_skip-worktree.mdwn +35/−0
- doc/bugs/git_defunct_processes___40__child_of_git-annex_assistant__41__.mdwn +34/−0
- doc/bugs/gpg_goes_to_100__37___cpu_on_bad_input_data.mdwn +2/−0
- doc/bugs/restart_daemon_required.mdwn +20/−0
- doc/bugs/wishlist:_make_git_annex_reinject_work_in_direct_mode.mdwn +18/−0
- doc/bugs/wishlist:_more_descriptive_commit_messages_in_git-annex_branch.mdwn +39/−0
- doc/design/assistant.mdwn +2/−2
- doc/design/assistant/OSX/comment_1_9290f6e6f265e906b08631224392b7bf._comment +14/−0
- doc/design/assistant/blog/day_270__release_and_xmpp.mdwn +39/−0
- doc/design/assistant/blog/day_271__more_xmpp.mdwn +31/−0
- doc/design/assistant/blog/day_272__fuzz_tester.mdwn +37/−0
- doc/design/assistant/blog/day_273-274__fun.mdwn +19/−0
- doc/design/assistant/blog/day_275__working_hard_or.mdwn +12/−0
- doc/design/assistant/blog/day_276__fuzzing_continues.mdwn +12/−0
- doc/design/assistant/blog/day_277__private_static_protected_void.mdwn +19/−0
- doc/design/assistant/blog/day_278__winding_down.mdwn +11/−0
- doc/design/assistant/blog/day_279__final_release_prep.mdwn +14/−0
- doc/design/assistant/blog/day_81__enabling_pre-existing_special_remotes.mdwn +34/−0
- doc/design/assistant/more_cloud_providers.mdwn +2/−1
- doc/design/assistant/polls/Android_default_directory.mdwn +1/−1
- doc/design/assistant/xmpp.mdwn +8/−5
- doc/forum/Help_with_syncing_file_contents.mdwn +68/−0
- doc/forum/How_to_prevent_the_assistant_from_downloading_all_data__63__.mdwn +9/−0
- doc/forum/Securing_a_shared_ssh_server.mdwn +3/−0
- doc/forum/Syncronisation_of_syncronisation_between_3_repositories__63__.mdwn +11/−0
- doc/forum/Use_local_files_instead_of_re-downloading_from_S3_remote.mdwn +3/−0
- doc/forum/XBMC__44___NFS___38___git-annex_.txt +27/−0
- doc/forum/flickrannex_--_not_sure_I_get_it.mdwn +7/−0
- doc/forum/glacier_-_range_retrievals_and_daily_free_retrieval_allowance.mdwn +6/−0
- doc/forum/help_running_git-annex_on_top_of_existing_repo.mdwn +12/−0
- doc/forum/mistakenly_checked___42__files__42___into_an_annex.__bummer..mdwn +3/−0
- doc/forum/ssh_password.mdwn +3/−0
- doc/forum/ssh_password/comment_1_a3e5a41e1d4da683d577976b134b11ee._comment +10/−0
- doc/forum/ssh_password/comment_2_fa261676a99d49d4b237b0d43048d76d._comment +10/−0
- doc/forum/switching_to__47__from_direct_mode_while_assistant_is_running.mdwn +2/−0
- doc/future_proofing.mdwn +1/−1
- doc/git-annex.mdwn +13/−0
- doc/install/Debian/comment_10_d5da996e106d2e4d8a822aa9bcc78596._comment +12/−0
- doc/install/Debian/comment_11_84283676da247c401bc9b4bb12c2b453._comment +8/−0
- doc/install/Debian/comment_7_1bccc7bf7a4ef61a9b30024b9b22ba7d._comment +12/−0
- doc/install/Debian/comment_8_5b5a3b0e8abe8831a6a15a4e258d14fd._comment +10/−0
- doc/install/Debian/comment_9_97eaed998ffd1ed79585075ed5cff06e._comment +8/−0
- doc/install/OSX.mdwn +1/−0
- doc/install/Ubuntu/comment_2_ad13886c1c1f76d1cd995ea7b7d8471c._comment +8/−0
- doc/install/Windows.mdwn +1/−1
- doc/install/cabal.mdwn +10/−1
- doc/install/cabal/comment_2_a69d17c55e56a707ec6606d5cdddee25._comment +17/−0
- doc/install/cabal/comment_3_55bed050bdb768543dbe1b86edec057d._comment +10/−0
- doc/install/cabal/comment_4_2ff7f8a3b03bea7e860248829d595bd1._comment +14/−0
- doc/install/cabal/comment_5_8789fc27466714faa5a3a7a6b8ec6e5d._comment +24/−0
- doc/install/cabal/comment_6_5afb2d081e8b603bc338cd460ad9317d._comment +21/−0
- doc/news/version_4.20130323.mdwn +0/−37
- doc/news/version_4.20130405.mdwn +0/−34
- doc/news/version_4.20130521.mdwn +24/−0
- doc/news/version_4.20130601.mdwn +25/−0
- doc/preferred_content.mdwn +4/−4
- doc/special_remotes.mdwn +10/−6
- doc/special_remotes/S3/comment_10_c366f020c9b97a365e21878a33360079._comment +10/−0
- doc/special_remotes/S3/comment_11_c1da387e082d91feec13dde91ccb111a._comment +12/−0
- doc/special_remotes/S3/comment_12_59c3ecab7dbc8be53258460473cac21c._comment +8/−0
- doc/special_remotes/S3/comment_13_0789a21d980825188bb09f7fc8bba8be._comment +33/−0
- doc/special_remotes/S3/comment_14_29574a51d5831c51e2e765eb2c06e567._comment +12/−0
- doc/special_remotes/S3/comment_9_7ad757b3865b04967c79af0a263bb3b0._comment +10/−0
- doc/special_remotes/bup/comment_10_f78c1ed97d2e4c6ebffaa7482cfe0c9b._comment +23/−0
- doc/special_remotes/bup/comment_11_b53bceb0058acf4d1ab12ea4853ee443._comment +24/−0
- doc/special_remotes/bup/comment_12_65d923226cf6120349d807c5c60f640c._comment +8/−0
- doc/special_remotes/bup/comment_1_96179a003da4444f6fc08867872cda0a._comment +43/−0
- doc/special_remotes/bup/comment_2_612b038c15206f9f3c2e23c7104ca627._comment +12/−0
- doc/special_remotes/bup/comment_3_1186def82741ddab1ade256fb2e59e6f._comment +17/−0
- doc/special_remotes/bup/comment_4_7d22a805dd2914971e7ca628ceea69be._comment +10/−0
- doc/special_remotes/bup/comment_6_5942333cde09fd98e26c4f1d389cb76f._comment +10/−0
- doc/special_remotes/bup/comment_7_cb1a0d3076e9d06e7a24204478f6fa98._comment +10/−0
- doc/special_remotes/bup/comment_8_4cbc67e5911748d13cee3c483d7ece8a._comment +12/−0
- doc/special_remotes/bup/comment_9_ca7096a759961af375e6bd49663b45b3._comment +10/−0
- doc/special_remotes/comment_12_13237170ef5b6646e0e25d3421af3fe5._comment +10/−0
- doc/special_remotes/comment_13_1a36a0483a9db04d36e0234a192ebad8._comment +12/−0
- doc/special_remotes/comment_14_a8419963dc024b1d9eb73807596012dc._comment +8/−0
- doc/special_remotes/comment_15_95ccfdd22a2391daa99e0beb04adedd6._comment +11/−0
- doc/special_remotes/comment_16_b9d238fb15ad7628e33c90b071e07bb0._comment +12/−0
- doc/special_remotes/comment_17_cc21b81a8f809f6efa5f5b6332513fc3._comment +12/−0
- doc/special_remotes/comment_18_3fe750118ff1edbe91a110b86fb5b662._comment +10/−0
- doc/special_remotes/comment_19_6794eb52bd87c28ef1df3172aa7d5780._comment +9/−0
- doc/special_remotes/hook.mdwn +36/−1
- doc/special_remotes/hook/comment_1_6a74a25891974a28a8cb42b87cb53c26._comment +32/−0
- doc/special_remotes/xmpp/comment_1_568247938929a2934e8198fca80b7184._comment +11/−0
- doc/special_remotes/xmpp/comment_2_9fc3f512020b7eb2591d6b7b2e8de2d7._comment +10/−0
- doc/templates/bugtemplate.mdwn +1/−1
- doc/tips/assume-unstaged/comment_1_44abd811ef79a85e557418e17a3927be._comment +10/−0
- doc/tips/dropboxannex.mdwn +28/−0
- doc/tips/flickrannex.mdwn +49/−0
- doc/tips/googledriveannex.mdwn +28/−0
- doc/tips/megaannex.mdwn +3/−7
- doc/tips/owncloudannex.mdwn +28/−0
- doc/tips/skydriveannex.mdwn +29/−0
- doc/tips/using_Amazon_S3/comment_1_666a26f95024760c99c627eed37b1966._comment +8/−0
- doc/tips/using_Amazon_S3/comment_2_f5a0883be7dbb421b584c6dc0165f1ef._comment +8/−0
- doc/todo/Build_for_Synology_DSM.mdwn +1/−0
- doc/todo/Use_a_remote_as_a_sharing_site_for_files_with_obfuscated_URLs.mdwn +7/−0
- doc/todo/cache_key_info/comment_1_578df1b3b2cbfdc4aa1805378f35dc48._comment +11/−0
- doc/todo/support_for_writing_external_special_remotes.mdwn +25/−0
- doc/todo/union_mounting/comment_1_cb08435812dd7766de26199c73f38e8b._comment +8/−0
- doc/todo/union_mounting/comment_2_240b1736f6bd4fbf87c372d3a46e661b._comment +9/−0
- doc/todo/windows_support/comment_1_3cc26ad8101a22e95a8c60cf0c4dedcc._comment +10/−0
- doc/todo/windows_support/comment_2_8acae818ce468967499050bbe3c532ea._comment +12/−0
- doc/todo/windows_support/comment_3_bd0a12f4c9b884ab8a06082842381a01._comment +8/−0
- doc/todo/windows_support/comment_4_ad06b98b2ddac866ffee334e41fee6a8._comment +8/−0
- doc/todo/windows_support/comment_5_444fc7251f57db241b6e80abae41851c._comment +10/−0
- doc/todo/windows_support/comment_6_34f1f60b570c389bb1e741b990064a7e._comment +8/−0
- doc/todo/wishlist:_Advanced_settings_for_xmpp_and_webdav.mdwn +2/−0
- doc/todo/wishlist:_Restore_s3_files_moved_to_Glacier.mdwn +7/−0
- doc/todo/wishlist:_git_annex_put_--_same_as_get__44___but_for_defaults.mdwn +17/−0
- doc/todo/wishlist:_vicfg_possible_repo_group_names.mdwn +16/−0
- git-annex.1 +12/−0
- git-annex.cabal +1/−1
- standalone/android/Makefile +2/−2
- standalone/android/haskell-patches/gsasl_0.3.5-0001-link-with-libgsasl.patch +25/−0
- standalone/android/haskell-patches/persistent_1.1.5.1_0001-disable-TH.patch +71/−0
- standalone/android/haskell-patches/shakespeare-js_1.1.2_0001-remove-TH.patch +308/−0
- standalone/android/haskell-patches/socks_0.4.2_0001-remove-IPv6-stuff.patch +107/−0
- standalone/android/icons/drawable-hdpi/ic_stat_service_notification_icon.png binary
- standalone/android/icons/drawable-ldpi/ic_stat_service_notification_icon.png binary
- standalone/android/icons/drawable-mdpi/ic_stat_service_notification_icon.png binary
- standalone/android/runshell +15/−10
- standalone/android/start.c +8/−4
- standalone/android/term.patch +525/−0
- standalone/linux/git-annex-shell +25/−0
- standalone/osx/git-annex.app/Contents/MacOS/git-annex-shell +25/−0
@@ -10,7 +10,6 @@ module Annex ( Annex, AnnexState(..),- FileInfo(..), PreferredContentMap, new, newState,@@ -55,6 +54,7 @@ import Types.Group import Types.Messages import Types.UUID+import Types.FileMatcher import qualified Utility.Matcher import qualified Data.Map as M import qualified Data.Set as S@@ -74,12 +74,6 @@ ) type Matcher a = Either [Utility.Matcher.Token a] (Utility.Matcher.Matcher a)--data FileInfo = FileInfo- { relFile :: FilePath -- may be relative to cwd- , matchFile :: FilePath -- filepath to match on; may be relative to top- }- type PreferredContentMap = M.Map UUID (Utility.Matcher.Matcher (S.Set UUID -> FileInfo -> Annex Bool)) -- internal state storage@@ -92,6 +86,7 @@ , force :: Bool , fast :: Bool , auto :: Bool+ , daemon :: Bool , branchstate :: BranchState , repoqueue :: Maybe Git.Queue.Queue , catfilehandles :: M.Map FilePath CatFileHandle@@ -122,6 +117,7 @@ , force = False , fast = False , auto = False+ , daemon = False , branchstate = startBranchState , repoqueue = Nothing , catfilehandles = M.empty
@@ -65,7 +65,7 @@ {- List of git-annex (refs, branches), including the main one and any - from remotes. Duplicate refs are filtered out. -} siblingBranches :: Annex [(Git.Ref, Git.Branch)]-siblingBranches = inRepo $ Git.Ref.matchingUniq name+siblingBranches = inRepo $ Git.Ref.matchingUniq [name] {- Creates the branch, if it does not already exist. -} create :: Annex ()
@@ -57,15 +57,36 @@ {- From the Sha or Ref of a symlink back to the key. -} catKey :: Ref -> Annex (Maybe Key) catKey ref = do- l <- fromInternalGitPath . encodeW8 . L.unpack <$> catObject ref+ l <- fromInternalGitPath . encodeW8 . L.unpack <$> catObject ref return $ if isLinkToAnnex l then fileKey $ takeFileName l else Nothing -{- From a file in git back to the key.+{- From a file in the repository back to the key. - - Prefixing the file with ./ makes this work even if in a subdirectory - of a repo.+ -+ - Ideally, this should reflect the key that's staged in the index,+ - not the key that's committed to HEAD. Unfortunately, git cat-file+ - does not refresh the index file after it's started up, so things+ - newly staged in the index won't show up. It does, however, notice+ - when branches change.+ -+ - For command-line git-annex use, that doesn't matter. It's perfectly+ - reasonable for things staged in the index after the currently running+ - git-annex process to not be noticed by it.+ -+ - For the assistant, this is much more of a problem, since it commits+ - files and then needs to be able to immediately look up their keys.+ - OTOH, the assistant doesn't keep changes staged in the index for very+ - long at all before committing them -- and it won't look at the keys+ - of files until after committing them.+ -+ - So, this gets info from the index, unless running as a daemon. -} catKeyFile :: FilePath -> Annex (Maybe Key)-catKeyFile f = catKey $ Ref $ ":./" ++ f+catKeyFile f = ifM (Annex.getState Annex.daemon)+ ( catKey $ Ref $ "HEAD:./" ++ f+ , catKey $ Ref $ ":./" ++ f+ )
@@ -115,7 +115,7 @@ a #else file <- calcRepo $ gitAnnexLocation key- bracketIO (openforlock file >>= lock) unlock a+ bracketIO (openforlock file >>= lock) unlock (const a) where {- Since files are stored with the write bit disabled, have - to fiddle with permissions to open for an exclusive lock. -}@@ -205,8 +205,7 @@ case (free, keySize key) of (Just have, Just need) -> do let ok = (need + reserve <= have + alreadythere) || force- unless ok $ do- liftIO $ print (need, reserve, have, alreadythere)+ unless ok $ needmorespace (need + reserve - have - alreadythere) return ok _ -> return True
@@ -193,7 +193,7 @@ compareInodeCachesWith = ifM inodesChanged ( return Weakly, return Strongly ) {- Copies the contentfile to the associated file, if the associated- - file has not content. If the associated file does have content,+ - file has no content. If the associated file does have content, - even if the content differs, it's left unchanged. -} addContentWhenNotPresent :: Key -> FilePath -> FilePath -> Annex () addContentWhenNotPresent key contentfile associatedfile = do
@@ -27,6 +27,7 @@ import Utility.CopyFile import Annex.Perms import Annex.ReplaceFile+import Annex.Exception {- Uses git ls-files to find files that need to be committed, and stages - them into the index. Returns True if some changes were staged. -}@@ -139,8 +140,10 @@ liftIO $ removeDirectoryRecursive d where updated item = do- go DiffTree.srcsha DiffTree.srcmode moveout moveout_raw- go DiffTree.dstsha DiffTree.dstmode movein movein_raw+ void $ tryAnnex $+ go DiffTree.srcsha DiffTree.srcmode moveout moveout_raw+ void $ tryAnnex $ + go DiffTree.dstsha DiffTree.dstmode movein movein_raw where go getsha getmode a araw | getsha item == nullSha = noop@@ -173,7 +176,8 @@ void $ tryIO $ rename (d </> f) f {- If possible, converts a symlink in the working tree into a direct- - mode file. -}+ - mode file. If the content is not available, leaves the symlink+ - unchanged. -} toDirect :: Key -> FilePath -> Annex () toDirect k f = fromMaybe noop =<< toDirectGen k f @@ -181,28 +185,30 @@ toDirectGen k f = do loc <- calcRepo $ gitAnnexLocation k ifM (liftIO $ doesFileExist loc)- ( fromindirect loc- , fromdirect+ ( return $ Just $ fromindirect loc+ , do+ {- Copy content from another direct file. -}+ absf <- liftIO $ absPath f+ locs <- filterM (\l -> isNothing <$> getAnnexLinkTarget l) =<<+ (filter (/= absf) <$> addAssociatedFile k f) + return $ Just $ fromdirect locs ) where- fromindirect loc = return $ Just $ do+ fromindirect loc = do {- Move content from annex to direct file. -} thawContentDir loc updateInodeCache k loc void $ addAssociatedFile k f thawContent loc replaceFile f $ liftIO . moveFile loc- fromdirect = do- {- Copy content from another direct file. -}- absf <- liftIO $ absPath f- locs <- filterM (\loc -> isNothing <$> getAnnexLinkTarget loc) =<<- (filter (/= absf) <$> addAssociatedFile k f)- case locs of- (loc:_) -> return $ Just $ do- replaceFile f $- liftIO . void . copyFileExternal loc- updateInodeCache k f- _ -> return Nothing+ fromdirect (loc:locs) = ifM (goodContent k loc)+ ( do+ replaceFile f $+ liftIO . void . copyFileExternal loc+ updateInodeCache k f+ , fromdirect locs+ )+ fromdirect [] = noop {- Removes a direct mode file, while retaining its content in the annex - (unless its content has already been changed). -}
@@ -24,9 +24,8 @@ import Common.Annex {- Runs an Annex action, with setup and cleanup both in the IO monad. -}-bracketIO :: IO c -> (c -> IO b) -> Annex a -> Annex a-bracketIO setup cleanup go =- bracket (liftIO setup) (liftIO . cleanup) (const go)+bracketIO :: IO v -> (v -> IO b) -> (v -> Annex a) -> Annex a+bracketIO setup cleanup go = bracket (liftIO setup) (liftIO . cleanup) go {- try in the Annex monad -} tryAnnex :: Annex a -> Annex (Either SomeException a)
@@ -17,6 +17,7 @@ import Logs.Remote import Annex.UUID import qualified Annex+import Types.FileMatcher import Git.FilePath import Types.Remote (RemoteConfig) @@ -33,9 +34,9 @@ | isEmpty matcher = return def | otherwise = do matchfile <- getTopFilePath <$> inRepo (toTopFilePath file)- let fi = Annex.FileInfo- { Annex.matchFile = matchfile- , Annex.relFile = file+ let fi = FileInfo+ { matchFile = matchfile+ , relFile = file } matchMrun matcher $ \a -> a notpresent fi
@@ -84,7 +84,7 @@ lockfile <- fromRepo gitAnnexJournalLock createAnnexDirectory $ takeDirectory lockfile mode <- annexFileMode- bracketIO (lock lockfile mode) unlock a+ bracketIO (lock lockfile mode) unlock (const a) where lock lockfile mode = do #ifndef __WINDOWS__
@@ -9,27 +9,32 @@ import Common.Annex import Annex.Perms+import Annex.Exception {- Replaces a possibly already existing file with a new version, - atomically, by running an action. - - The action is passed a temp file, which it can write to, and once - done the temp file is moved into place.+ -+ - The action can throw an IO exception, in which case the temp file+ - will be deleted, and the existing file will be preserved.+ -+ - Throws an IO exception when it was unable to replace the file. -} replaceFile :: FilePath -> (FilePath -> Annex ()) -> Annex () replaceFile file a = do tmpdir <- fromRepo gitAnnexTmpDir- createAnnexDirectory tmpdir- tmpfile <- liftIO $ do+ void $ createAnnexDirectory tmpdir+ bracketIO (setup tmpdir) nukeFile $ \tmpfile -> do+ a tmpfile+ liftIO $ catchIO (rename tmpfile file) (fallback tmpfile)+ where+ setup tmpdir = do (tmpfile, h) <- openTempFileWithDefaultPermissions tmpdir $ takeFileName file hClose h return tmpfile- a tmpfile- liftIO $ do- r <- tryIO $ rename tmpfile file- case r of- Left _ -> do- createDirectoryIfMissing True $ parentDir file- rename tmpfile file- _ -> noop+ fallback tmpfile _ = do+ createDirectoryIfMissing True $ parentDir file+ rename tmpfile file
@@ -1,126 +1,15 @@ {- git-annex assistant daemon -- - Copyright 2012 Joey Hess <joey@kitenet.net>+ - Copyright 2012-2013 Joey Hess <joey@kitenet.net> - - Licensed under the GNU GPL version 3 or higher.- -- - Overview of threads and MVars, etc:- -- - Thread 1: parent- - The initial thread run, double forks to background, starts other- - threads, and then stops, waiting for them to terminate,- - or for a ctrl-c.- - Thread 2: Watcher- - Notices new files, and calls handlers for events, queuing changes.- - Thread 3: inotify internal- - Used by haskell inotify library to ensure inotify event buffer is- - kept drained.- - Thread 4: inotify startup scanner- - Scans the tree and registers inotify watches for each directory.- - A MVar lock is used to prevent other inotify handlers from running- - until this is complete.- - Thread 5: Committer- - Waits for changes to occur, and runs the git queue to update its- - index, then commits. Also queues Transfer events to send added- - files to other remotes.- - Thread 6: Pusher- - Waits for commits to be made, and pushes updated branches to remotes,- - in parallel. (Forks a process for each git push.)- - Thread 7: PushRetryer- - Runs every 30 minutes when there are failed pushes, and retries- - them.- - Thread 8: Merger- - Waits for pushes to be received from remotes, and merges the- - updated branches into the current branch.- - (This uses inotify on .git/refs/heads, so there are additional- - inotify threads associated with it, too.)- - Thread 9: TransferWatcher- - Watches for transfer information files being created and removed,- - and maintains the DaemonStatus currentTransfers map.- - (This uses inotify on .git/annex/transfer/, so there are- - additional inotify threads associated with it, too.)- - Thread 10: TransferPoller- - Polls to determine how much of each ongoing transfer is complete.- - Thread 11: Transferrer- - Waits for Transfers to be queued and does them.- - Thread 12: StatusLogger- - Wakes up periodically and records the daemon's status to disk.- - Thread 13: SanityChecker- - Wakes up periodically (rarely) and does sanity checks.- - Thread 14: MountWatcher- - Either uses dbus to watch for drive mount events, or, when- - there's no dbus, polls to find newly mounted filesystems.- - Once a filesystem that contains a remote is mounted, updates- - state about that remote, pulls from it, and queues a push to it,- - as well as an update, and queues it onto the- - ConnectedRemoteChan- - Thread 15: NetWatcher- - Deals with network connection interruptions, which would cause- - transfers to fail, and can be recovered from by waiting for a- - network connection, and syncing with all network remotes.- - Uses dbus to watch for network connections, or when dbus- - cannot be used, assumes there's been one every 30 minutes.- - Thread 16: TransferScanner- - Does potentially expensive checks to find data that needs to be- - transferred from or to remotes, and queues Transfers.- - Uses the ScanRemotes map.a- - Thread 17: PairListener- - Listens for incoming pairing traffic, and takes action.- - Thread 18: ConfigMonitor- - Triggered by changes to the git-annex branch, checks for changed- - config files, and reloads configs.- - Thread 19: XMPPClient- - Built-in XMPP client.- - Thread 20: WebApp- - Spawns more threads as necessary to handle clients.- - Displays the DaemonStatus.- - Thread 21: Glacier- - Deals with retrieving files from Amazon Glacier.- -- - ThreadState: (MVar)- - The Annex state is stored here, which allows resuscitating the- - Annex monad in IO actions run by the watcher and committer- - threads. Thus, a single state is shared amoung the threads, and- - only one at a time can access it.- - DaemonStatusHandle: (STM TMVar)- - The daemon's current status.- - ChangeChan: (STM TChan)- - Changes are indicated by writing to this channel. The committer- - reads from it.- - CommitChan: (STM TChan)- - Commits are indicated by writing to this channel. The pusher reads- - from it.- - FailedPushMap (STM TMVar)- - Failed pushes are indicated by writing to this TMVar. The push- - retrier blocks until they're available.- - TransferQueue (STM TChan)- - Transfers to make are indicated by writing to this channel.- - TransferSlots (QSemN)- - Count of the number of currently available transfer slots.- - Updated by the transfer watcher, this allows other threads- - to block until a slot is available.- - This MVar should only be manipulated from inside the Annex monad,- - which ensures it's accessed only after the ThreadState MVar.- - ScanRemotes (STM TMVar)- - Remotes that have been disconnected, and should be scanned- - are indicated by writing to this TMVar.- - BranchChanged (STM SampleVar)- - Changes to the git-annex branch are indicated by updating this- - SampleVar.- - NetMessager (STM TChan, TMVar, SampleVar)- - Used to feed messages to the built-in XMPP client, handle- - pushes, and signal it when it needs to restart due to configuration- - or networking changes.- - UrlRenderer (MVar)- - A Yesod route rendering function is stored here. This allows- - things that need to render Yesod routes to block until the webapp- - has started up and such rendering is possible. -} {-# LANGUAGE CPP #-} module Assistant where +import qualified Annex import Assistant.Common import Assistant.DaemonStatus import Assistant.NamedThread@@ -149,6 +38,7 @@ #endif #ifdef WITH_XMPP import Assistant.Threads.XMPPClient+import Assistant.Threads.XMPPPusher #endif #else #warning Building without the webapp. You probably need to install Yesod..@@ -172,6 +62,7 @@ - stdout and stderr descriptors. -} startDaemon :: Bool -> Bool -> Maybe HostName -> Maybe (Maybe Handle -> Maybe Handle -> String -> FilePath -> IO ()) -> Annex () startDaemon assistant foreground listenhost startbrowser = do+ Annex.changeState $ \s -> s { Annex.daemon = True } pidfile <- fromRepo gitAnnexPidFile logfile <- fromRepo gitAnnexLogFile logfd <- liftIO $ openLog logfile@@ -223,6 +114,8 @@ #endif #ifdef WITH_XMPP , assist $ xmppClientThread urlrenderer+ , assist $ xmppSendPackThread urlrenderer+ , assist $ xmppReceivePackThread urlrenderer #endif #endif , assist $ pushThread
binary file changed (3364 → 3364 bytes)
binary file changed (3216 → 3216 bytes)
@@ -1,21 +1,22 @@ {- git-annex assistant out of band network messager interface -- - Copyright 2012 Joey Hess <joey@kitenet.net>+ - Copyright 2012-2013 Joey Hess <joey@kitenet.net> - - Licensed under the GNU GPL version 3 or higher. -} +{-# LANGUAGE BangPatterns #-}+ module Assistant.NetMessager where import Assistant.Common import Assistant.Types.NetMessager -import Control.Concurrent import Control.Concurrent.STM import Control.Concurrent.MSampleVar-import Control.Exception as E import qualified Data.Set as S import qualified Data.Map as M+import qualified Data.DList as D sendNetMessage :: NetMessage -> Assistant () sendNetMessage m = @@ -31,8 +32,9 @@ waitNetMessagerRestart :: Assistant () waitNetMessagerRestart = readSV <<~ (netMessagerRestart . netMessager) -{- Store an important NetMessage for a client, and if the same message was- - already sent, remove it from sentImportantNetMessages. -}+{- Store a new important NetMessage for a client, and if an equivilant+ - older message is already stored, remove it from both importantNetMessages+ - and sentImportantNetMessages. -} storeImportantNetMessage :: NetMessage -> ClientID -> (ClientID -> Bool) -> Assistant () storeImportantNetMessage m client matchingclient = go <<~ netMessager where@@ -40,11 +42,12 @@ q <- takeTMVar $ importantNetMessages nm sent <- takeTMVar $ sentImportantNetMessages nm putTMVar (importantNetMessages nm) $- M.alter (Just . maybe (S.singleton m) (S.insert m)) client q+ M.alter (Just . maybe (S.singleton m) (S.insert m)) client $+ M.mapWithKey removematching q putTMVar (sentImportantNetMessages nm) $ M.mapWithKey removematching sent removematching someclient s- | matchingclient someclient = S.delete m s+ | matchingclient someclient = S.filter (not . equivilantImportantNetMessages m) s | otherwise = s {- Indicates that an important NetMessage has been sent to a client. -}@@ -67,66 +70,107 @@ sent <- M.lookup sentclient <$> (readTMVar $ sentImportantNetMessages nm) return (fromMaybe S.empty stored, fromMaybe S.empty sent) -{- Runs an action that runs either the send or receive side of a push.- -- - While the push is running, netMessagesPush will get messages put into it- - relating to this push, while any messages relating to other pushes- - on the same side go to netMessagesDeferred. Once the push finishes,- - those deferred messages will be fed to handledeferred for processing.- -}-runPush :: PushSide -> ClientID -> (NetMessage -> Assistant ()) -> Assistant a -> Assistant a-runPush side clientid handledeferred a = do- nm <- getAssistant netMessager- let runningv = getSide side $ netMessagerPushRunning nm- let setup = void $ atomically $ swapTMVar runningv $ Just clientid- let cleanup = atomically $ do- void $ swapTMVar runningv Nothing- emptytchan (getSide side $ netMessagesPush nm)- r <- E.bracket_ setup cleanup <~> a- (void . forkIO) <~> processdeferred nm- return r+{- Queues a push initiation message in the queue for the appropriate+ - side of the push but only if there is not already an initiation message+ - from the same client in the queue. -}+queuePushInitiation :: NetMessage -> Assistant ()+queuePushInitiation msg@(Pushing clientid stage) = do+ tv <- getPushInitiationQueue side+ liftIO $ atomically $ do+ r <- tryTakeTMVar tv+ case r of+ Nothing -> putTMVar tv [msg]+ Just l -> do+ let !l' = msg : filter differentclient l+ putTMVar tv l' where- emptytchan c = maybe noop (const $ emptytchan c) =<< tryReadTChan c- processdeferred nm = do- s <- liftIO $ atomically $ swapTMVar (getSide side $ netMessagesPushDeferred nm) S.empty- mapM_ rundeferred (S.toList s)- rundeferred m = (void . (E.try :: (IO () -> IO (Either SomeException ()))))- <~> handledeferred m+ side = pushDestinationSide stage+ differentclient (Pushing cid _) = cid /= clientid+ differentclient _ = True+queuePushInitiation _ = noop -{- While a push is running, matching push messages are put into- - netMessagesPush, while others that involve the same side go to- - netMessagesPushDeferred.+{- Waits for a push inititation message to be received, and runs+ - function to select a message from the queue. -}+waitPushInitiation :: PushSide -> ([NetMessage] -> (NetMessage, [NetMessage])) -> Assistant NetMessage+waitPushInitiation side selector = do+ tv <- getPushInitiationQueue side+ liftIO $ atomically $ do+ q <- takeTMVar tv+ if null q+ then retry+ else do+ let (msg, !q') = selector q+ unless (null q') $+ putTMVar tv q'+ return msg++{- Stores messages for a push into the appropriate inbox. -- - When no push is running involving the same side, returns False.+ - To avoid overflow, only 1000 messages max are stored in any+ - inbox, which should be far more than necessary. -- - To avoid bloating memory, only messages that initiate pushes are- - deferred.+ - TODO: If we have more than 100 inboxes for different clients,+ - discard old ones that are not currently being used by any push. -}-queueNetPushMessage :: NetMessage -> Assistant Bool-queueNetPushMessage m@(Pushing clientid stage) = do- nm <- getAssistant netMessager- liftIO $ atomically $ do- v <- readTMVar (getSide side $ netMessagerPushRunning nm)- case v of- Nothing -> return False- (Just runningclientid)- | runningclientid == clientid -> queue nm- | isPushInitiation stage -> defer nm- | otherwise -> discard+storeInbox :: NetMessage -> Assistant ()+storeInbox msg@(Pushing clientid stage) = do+ inboxes <- getInboxes side+ stored <- liftIO $ atomically $ do+ m <- readTVar inboxes+ let update = \v -> do+ writeTVar inboxes $+ M.insertWith' const clientid v m+ return True+ case M.lookup clientid m of+ Nothing -> update (1, tostore)+ Just (sz, l)+ | sz > 1000 -> return False+ | otherwise ->+ let !sz' = sz + 1+ !l' = D.append l tostore+ in update (sz', l')+ if stored+ then netMessagerDebug clientid ["stored", logNetMessage msg, "in", show side, "inbox"]+ else netMessagerDebug clientid ["discarded", logNetMessage msg, "; ", show side, "inbox is full"] where side = pushDestinationSide stage- queue nm = do- writeTChan (getSide side $ netMessagesPush nm) m- return True- defer nm = do- let mv = getSide side $ netMessagesPushDeferred nm- s <- takeTMVar mv- putTMVar mv $ S.insert m s- return True- discard = return True-queueNetPushMessage _ = return False+ tostore = D.singleton msg+storeInbox _ = noop -waitNetPushMessage :: PushSide -> Assistant (NetMessage)-waitNetPushMessage side = (atomically . readTChan)- <<~ (getSide side . netMessagesPush . netMessager)+{- Gets the new message for a push from its inbox.+ - Blocks until a message has been received. -}+waitInbox :: ClientID -> PushSide -> Assistant (NetMessage)+waitInbox clientid side = do+ inboxes <- getInboxes side+ liftIO $ atomically $ do+ m <- readTVar inboxes+ case M.lookup clientid m of+ Nothing -> retry+ Just (sz, dl)+ | sz < 1 -> retry+ | otherwise -> do+ let msg = D.head dl+ let dl' = D.tail dl+ let !sz' = sz - 1+ writeTVar inboxes $+ M.insertWith' const clientid (sz', dl') m+ return msg +emptyInbox :: ClientID -> PushSide -> Assistant ()+emptyInbox clientid side = do+ inboxes <- getInboxes side+ liftIO $ atomically $+ modifyTVar' inboxes $+ M.delete clientid+ +getInboxes :: PushSide -> Assistant Inboxes+getInboxes side =+ getSide side . netMessagerInboxes <$> getAssistant netMessager++getPushInitiationQueue :: PushSide -> Assistant (TMVar [NetMessage])+getPushInitiationQueue side =+ getSide side . netMessagerPushInitiations <$> getAssistant netMessager++netMessagerDebug :: ClientID -> [String] -> Assistant ()+netMessagerDebug clientid l = debug $+ "NetMessager" : l ++ [show $ logClientID clientid]
@@ -20,6 +20,7 @@ import qualified Git import qualified Git.Branch import qualified Git.Command+import qualified Git.Ref import qualified Remote import qualified Types.Remote as Remote import qualified Annex.Branch@@ -112,8 +113,12 @@ <*> getUUID let (xmppremotes, normalremotes) = partition isXMPPRemote remotes ret <- go True branch g u normalremotes- forM_ xmppremotes $ \r ->- sendNetMessage $ Pushing (getXMPPClientID r) (CanPush u)+ unless (null xmppremotes) $ do+ shas <- liftAnnex $ map fst <$>+ inRepo (Git.Ref.matchingWithHEAD+ [Annex.Branch.fullname, Git.Ref.headRef])+ forM_ xmppremotes $ \r -> sendNetMessage $+ Pushing (getXMPPClientID r) (CanPush u shas) return ret where go _ Nothing _ _ _ = return [] -- no branch, so nothing to do
@@ -226,7 +226,6 @@ | symlinkssupported = a | otherwise = do linktarget <- liftAnnex $ getAnnexLinkTarget file- liftIO $ print (file, linktarget) case linktarget of Nothing -> a Just lt -> do
@@ -20,7 +20,6 @@ import Utility.ThreadScheduler import Assistant.WebApp (UrlRenderer) import Assistant.WebApp.Types hiding (liftAssistant)-import Assistant.WebApp.Configurators.XMPP (checkCloudRepos) import Assistant.Alert import Assistant.Pairing import Assistant.XMPP.Git@@ -29,11 +28,14 @@ import Network.Protocol.XMPP import Control.Concurrent+import Control.Concurrent.STM.TMVar+import Control.Concurrent.STM (atomically) import qualified Data.Text as T import qualified Data.Set as S import qualified Data.Map as M import qualified Git.Branch import Data.Time.Clock+import Control.Concurrent.Async xmppClientThread :: UrlRenderer -> NamedThread xmppClientThread urlrenderer = namedThread "XMPPClient" $@@ -65,16 +67,16 @@ - is not retained. -} liftAssistant $ updateBuddyList (const noBuddies) <<~ buddyList- e <- client+ void client liftAssistant $ modifyDaemonStatus_ $ \s -> s { xmppClientID = Nothing } now <- getCurrentTime if diffUTCTime now starttime > 300 then do- liftAssistant $ debug ["connection lost; reconnecting", show e]+ liftAssistant $ debug ["connection lost; reconnecting"] retry client now else do- liftAssistant $ debug ["connection failed; will retry", show e]+ liftAssistant $ debug ["connection failed; will retry"] threadDelaySeconds (Seconds 300) retry client =<< getCurrentTime @@ -87,17 +89,44 @@ { xmppClientID = Just $ xmppJID creds } debug ["connected", logJid selfjid] - xmppThread $ receivenotifications selfjid- forever $ do- a <- inAssistant $ relayNetMessage selfjid- a+ lasttraffic <- liftIO $ atomically . newTMVar =<< getCurrentTime - receivenotifications selfjid = forever $ do+ sender <- xmppSession $ sendnotifications selfjid+ receiver <- xmppSession $ receivenotifications selfjid lasttraffic+ pinger <- xmppSession $ sendpings selfjid lasttraffic+ {- Run all 3 threads concurrently, until+ - any of them throw an exception.+ - Then kill all 3 threads, and rethrow the+ - exception.+ -+ - If this thread gets an exception, the 3 threads+ - will also be killed. -}+ liftIO $ pinger `concurrently` sender `concurrently` receiver++ sendnotifications selfjid = forever $ do+ a <- inAssistant $ relayNetMessage selfjid+ a+ receivenotifications selfjid lasttraffic = forever $ do l <- decodeStanza selfjid <$> getStanza+ void $ liftIO $ atomically . swapTMVar lasttraffic =<< getCurrentTime inAssistant $ debug ["received:", show $ map logXMPPEvent l] mapM_ (handle selfjid) l+ sendpings selfjid lasttraffic = forever $ do+ putStanza pingstanza + startping <- liftIO $ getCurrentTime+ liftIO $ threadDelaySeconds (Seconds 120)+ t <- liftIO $ atomically $ readTMVar lasttraffic+ when (t < startping) $ do+ inAssistant $ debug ["ping timeout"]+ error "ping timeout"+ where+ {- XEP-0199 says that the server will respond with either+ - a ping response or an error message. Either will+ - cause traffic, so good enough. -}+ pingstanza = xmppPing selfjid+ handle selfjid (PresenceMessage p) = do void $ inAssistant $ updateBuddyList (updateBuddies p) <<~ buddyList@@ -107,11 +136,9 @@ handle selfjid (GotNetMessage (PairingNotification stage c u)) = maybe noop (inAssistant . pairMsgReceived urlrenderer stage u selfjid) (parseJID c) handle _ (GotNetMessage m@(Pushing _ pushstage))- | isPushInitiation pushstage = inAssistant $- unlessM (queueNetPushMessage m) $ do- let checker = checkCloudRepos urlrenderer- void $ forkIO <~> handlePushInitiation checker m- | otherwise = void $ inAssistant $ queueNetPushMessage m+ | isPushNotice pushstage = inAssistant $ handlePushNotice m+ | isPushInitiation pushstage = inAssistant $ queuePushInitiation m+ | otherwise = inAssistant $ storeInbox m handle _ (Ignorable _) = noop handle _ (Unknown _) = noop handle _ (ProtocolError _) = noop@@ -144,7 +171,9 @@ logXMPPEvent (GotNetMessage m) = logNetMessage m logXMPPEvent (PresenceMessage p) = logPresence p logXMPPEvent (Ignorable (ReceivedPresence p)) = "Ignorable " ++ logPresence p-logXMPPEvent v = show v+logXMPPEvent (Ignorable _) = "Ignorable message"+logXMPPEvent (Unknown _) = "Unknown message"+logXMPPEvent (ProtocolError _) = "Protocol error message" logPresence :: Presence -> String logPresence (p@Presence { presenceFrom = Just jid }) = unwords@@ -247,13 +276,12 @@ withClient :: ClientID -> (JID -> XMPP ()) -> XMPP () withClient c a = maybe noop a $ parseJID c -{- Runs a XMPP action in a separate thread, using a session to allow it- - to access the same XMPP client. -}-xmppThread :: XMPP () -> XMPP ()-xmppThread a = do+{- Returns an IO action that runs a XMPP action in a separate thread,+ - using a session to allow it to access the same XMPP client. -}+xmppSession :: XMPP () -> XMPP (IO ())+xmppSession a = do s <- getSession- void $ liftIO $ forkIO $- void $ runXMPP s a+ return $ void $ runXMPP s a {- We only pull from one remote out of the set listed in the push - notification, as an optimisation.
@@ -0,0 +1,81 @@+{- git-annex XMPP pusher threads+ -+ - This is a pair of threads. One handles git send-pack,+ - and the other git receive-pack. Each thread can be running at most+ - one such operation at a time.+ -+ - Why not use a single thread? Consider two clients A and B.+ - If both decide to run a receive-pack at the same time to the other,+ - they would deadlock with only one thread. For larger numbers of+ - clients, the two threads are also sufficient.+ -+ - Copyright 2013 Joey Hess <joey@kitenet.net>+ -+ - Licensed under the GNU GPL version 3 or higher.+ -}++module Assistant.Threads.XMPPPusher where++import Assistant.Common+import Assistant.NetMessager+import Assistant.Types.NetMessager+import Assistant.WebApp (UrlRenderer)+import Assistant.WebApp.Configurators.XMPP (checkCloudRepos)+import Assistant.XMPP.Git++import Control.Exception as E++xmppSendPackThread :: UrlRenderer -> NamedThread+xmppSendPackThread = pusherThread "XMPPSendPack" SendPack++xmppReceivePackThread :: UrlRenderer -> NamedThread+xmppReceivePackThread = pusherThread "XMPPReceivePack" ReceivePack++pusherThread :: String -> PushSide -> UrlRenderer -> NamedThread+pusherThread threadname side urlrenderer = namedThread threadname $ go Nothing+ where+ go lastpushedto = do+ msg <- waitPushInitiation side $ selectNextPush lastpushedto+ debug ["started running push", logNetMessage msg]++ runpush <- asIO $ runPush checker msg+ r <- liftIO (E.try runpush :: IO (Either SomeException (Maybe ClientID)))+ let successful = case r of+ Right (Just _) -> True+ _ -> False++ {- Empty the inbox, because stuff may have+ - been left in it if the push failed. -}+ let justpushedto = getclient msg+ maybe noop (`emptyInbox` side) justpushedto++ debug ["finished running push", logNetMessage msg, show successful]+ go $ if successful then justpushedto else lastpushedto+ + checker = checkCloudRepos urlrenderer++ getclient (Pushing cid _) = Just cid+ getclient _ = Nothing++{- Select the next push to run from the queue.+ - The queue cannot be empty!+ -+ - We prefer to select the most recently added push, because its requestor+ - is more likely to still be connected.+ -+ - When passed the ID of a client we just pushed to, we prefer to not+ - immediately push again to that same client. This avoids one client + - drowing out others. So pushes from the client we just pushed to are + - relocated to the beginning of the list, to be processed later.+ -}+selectNextPush :: Maybe ClientID -> [NetMessage] -> (NetMessage, [NetMessage])+selectNextPush _ (m:[]) = (m, []) -- common case+selectNextPush _ [] = error "selectNextPush: empty list"+selectNextPush lastpushedto l = go [] l+ where+ go (r:ejected) [] = (r, ejected)+ go rejected (m:ms) = case m of+ (Pushing clientid _)+ | Just clientid /= lastpushedto -> (m, rejected ++ ms)+ _ -> go (m:rejected) ms+ go [] [] = undefined
@@ -9,15 +9,17 @@ import Common.Annex import Assistant.Pairing+import Git.Types +import qualified Data.Text as T+import qualified Data.Set as S+import qualified Data.Map as M+import qualified Data.DList as D import Control.Concurrent.STM import Control.Concurrent.MSampleVar import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as B8 import Data.Text (Text)-import qualified Data.Text as T-import qualified Data.Set as S-import qualified Data.Map as M {- Messages that can be sent out of band by a network messager. -} data NetMessage @@ -37,7 +39,7 @@ data PushStage -- indicates that we have data to push over the out of band network- = CanPush UUID+ = CanPush UUID [Sha] -- request that a git push be sent over the out of band network | PushRequest UUID -- indicates that a push is starting@@ -58,10 +60,18 @@ {- NetMessages that are important (and small), and should be stored to be - resent when new clients are seen. -} isImportantNetMessage :: NetMessage -> Maybe ClientID-isImportantNetMessage (Pushing c (CanPush _)) = Just c+isImportantNetMessage (Pushing c (CanPush _ _)) = Just c isImportantNetMessage (Pushing c (PushRequest _)) = Just c isImportantNetMessage _ = Nothing +{- Checks if two important NetMessages are equivilant.+ - That is to say, assuming they were sent to the same client,+ - would it do the same thing for one as for the other? -}+equivilantImportantNetMessages :: NetMessage -> NetMessage -> Bool+equivilantImportantNetMessages (Pushing _ (CanPush _ _)) (Pushing _ (CanPush _ _)) = True+equivilantImportantNetMessages (Pushing _ (PushRequest _)) (Pushing _ (PushRequest _)) = True+equivilantImportantNetMessages _ _ = False+ readdressNetMessage :: NetMessage -> ClientID -> NetMessage readdressNetMessage (PairingNotification stage _ uuid) c = PairingNotification stage c uuid readdressNetMessage (Pushing _ stage) c = Pushing c stage@@ -85,16 +95,19 @@ {- Things that initiate either side of a push, but do not actually send data. -} isPushInitiation :: PushStage -> Bool-isPushInitiation (CanPush _) = True isPushInitiation (PushRequest _) = True isPushInitiation (StartingPush _) = True isPushInitiation _ = False +isPushNotice :: PushStage -> Bool+isPushNotice (CanPush _ _) = True+isPushNotice _ = False+ data PushSide = SendPack | ReceivePack- deriving (Eq, Ord)+ deriving (Eq, Ord, Show) pushDestinationSide :: PushStage -> PushSide-pushDestinationSide (CanPush _) = ReceivePack+pushDestinationSide (CanPush _ _) = ReceivePack pushDestinationSide (PushRequest _) = SendPack pushDestinationSide (StartingPush _) = ReceivePack pushDestinationSide (ReceivePackOutput _ _) = SendPack@@ -114,6 +127,8 @@ getSide :: PushSide -> SideMap a -> a getSide side m = m side +type Inboxes = TVar (M.Map ClientID (Int, D.DList NetMessage))+ data NetMessager = NetMessager -- outgoing messages { netMessages :: TChan NetMessage@@ -123,12 +138,11 @@ , sentImportantNetMessages :: TMVar (M.Map ClientID (S.Set NetMessage)) -- write to this to restart the net messager , netMessagerRestart :: MSampleVar ()- -- only one side of a push can be running at a time- , netMessagerPushRunning :: SideMap (TMVar (Maybe ClientID))- -- incoming messages related to a running push- , netMessagesPush :: SideMap (TChan NetMessage)- -- incoming push messages, deferred to be processed later- , netMessagesPushDeferred :: SideMap (TMVar (S.Set NetMessage))+ -- queue of incoming messages that request the initiation of pushes+ , netMessagerPushInitiations :: SideMap (TMVar [NetMessage])+ -- incoming messages containing data for a running+ -- (or not yet started) push+ , netMessagerInboxes :: SideMap Inboxes } newNetMessager :: IO NetMessager@@ -137,6 +151,5 @@ <*> atomically (newTMVar M.empty) <*> atomically (newTMVar M.empty) <*> newEmptySV- <*> mkSideMap (newTMVar Nothing)- <*> mkSideMap newTChan- <*> mkSideMap (newTMVar S.empty)+ <*> mkSideMap newEmptyTMVar+ <*> mkSideMap (newTVar M.empty)
@@ -21,17 +21,15 @@ import Assistant.NetMessager import Assistant.Alert import Assistant.DaemonStatus-import Utility.SRV import Assistant.WebApp.RepoList import Assistant.WebApp.Configurators import Assistant.XMPP #endif #ifdef WITH_XMPP-import Network import Network.Protocol.XMPP+import Network import qualified Data.Text as T-import Control.Exception (SomeException) #endif {- Displays an alert suggesting to configure XMPP. -}@@ -118,7 +116,7 @@ creds2Form <$> oldcreds let showform problem = $(widgetFile "configurators/xmpp") case result of- FormSuccess f -> either (showform . Just . show) (lift . storecreds)+ FormSuccess f -> either (showform . Just) (lift . storecreds) =<< liftIO (validateForm f) _ -> showform Nothing where@@ -184,32 +182,38 @@ bad :: Text bad = "This should look like an email address.." -validateForm :: XMPPForm -> IO (Either SomeException XMPPCreds)+validateForm :: XMPPForm -> IO (Either String XMPPCreds) validateForm f = do let jid = fromMaybe (error "bad JID") $ parseJID (formJID f)- let domain = T.unpack $ strDomain $ jidDomain jid- hostports <- lookupSRV $ mkSRVTcp "xmpp-client" domain let username = fromMaybe "" (strNode <$> jidNode jid)- case hostports of- ((h, PortNumber p):_) -> testXMPP $ XMPPCreds- { xmppUsername = username- , xmppPassword = formPassword f- , xmppHostname = h+ testXMPP $ XMPPCreds+ { xmppUsername = username+ , xmppPassword = formPassword f+ , xmppHostname = T.unpack $ strDomain $ jidDomain jid+ , xmppPort = 5222+ , xmppJID = formJID f+ }++testXMPP :: XMPPCreds -> IO (Either String XMPPCreds)+testXMPP creds = do+ (good, bad) <- partition (either (const False) (const True) . snd) + <$> connectXMPP creds (const noop)+ case good of+ (((h, PortNumber p), _):_) -> return $ Right $ creds+ { xmppHostname = h , xmppPort = fromIntegral p- , xmppJID = formJID f }- _ -> testXMPP $ XMPPCreds- { xmppUsername = username- , xmppPassword = formPassword f- , xmppHostname = T.unpack $ strDomain $ jidDomain jid- , xmppPort = 5222- , xmppJID = formJID f+ (((h, _), _):_) -> return $ Right $ creds+ { xmppHostname = h }--testXMPP :: XMPPCreds -> IO (Either SomeException XMPPCreds)-testXMPP creds = either Left (const $ Right creds)- <$> connectXMPP creds (const noop)+ _ -> return $ Left $ intercalate "; " $ map formatlog bad+ where+ formatlog ((h, p), Left e) = "host " ++ h ++ ":" ++ showport p ++ " failed: " ++ show e+ formatlog _ = "" + showport (PortNumber n) = show n+ showport (Service s) = s+ showport (UnixSocket s) = s #endif xmppPage :: Widget -> Handler RepHtml
@@ -1,6 +1,6 @@ {- core xmpp support -- - Copyright 2012 Joey Hess <joey@kitenet.net>+ - Copyright 2012-2013 Joey Hess <joey@kitenet.net> - - Licensed under the GNU GPL version 3 or higher. -}@@ -12,6 +12,7 @@ import Assistant.Common import Assistant.Types.NetMessager import Assistant.Pairing+import Git.Sha (extractSha) import Network.Protocol.XMPP hiding (Node) import Data.Text (Text)@@ -83,6 +84,18 @@ gitAnnexSignature :: Presence gitAnnexSignature = gitAnnexPresence $ Element gitAnnexTagName [] [] +{- XMPP client to server ping -}+xmppPing :: JID -> IQ+xmppPing selfjid = (emptyIQ IQGet)+ { iqID = Just "c2s1"+ , iqFrom = Just selfjid+ , iqTo = Just $ JID Nothing (jidDomain selfjid) Nothing+ , iqPayload = Just $ Element xmppPingTagName [] []+ }++xmppPingTagName :: Name+xmppPingTagName = "{urn:xmpp}ping"+ {- A message with a git-annex tag in it. -} gitAnnexMessage :: Element -> JID -> JID -> Message gitAnnexMessage elt tojid fromjid = (insertGitAnnexTag silentMessage elt)@@ -131,8 +144,9 @@ pushMessage :: PushStage -> JID -> JID -> Message pushMessage = gitAnnexMessage . encode where- encode (CanPush u) =- gitAnnexTag canPushAttr $ T.pack $ fromUUID u+ encode (CanPush u shas) =+ gitAnnexTag canPushAttr $ T.pack $ unwords $+ fromUUID u : map show shas encode (PushRequest u) = gitAnnexTag pushRequestAttr $ T.pack $ fromUUID u encode (StartingPush u) =@@ -160,7 +174,7 @@ , receivePackDoneAttr ] [ decodePairingNotification- , pushdecoder $ gen CanPush+ , pushdecoder $ shasgen CanPush , pushdecoder $ gen PushRequest , pushdecoder $ gen StartingPush , pushdecoder $ seqgen ReceivePackOutput@@ -172,11 +186,14 @@ pushdecoder a m' i = Pushing <$> (formatJID <$> messageFrom m') <*> a i- gen c = Just . c . toUUID . T.unpack . tagValue+ gen c i = c . toUUID <$> headMaybe (words (T.unpack (tagValue i))) seqgen c i = do packet <- decodeTagContent $ tagElement i let seqnum = fromMaybe 0 $ readish $ T.unpack $ tagValue i return $ c seqnum packet+ shasgen c i = do+ let (u:shas) = words $ T.unpack $ tagValue i+ return $ c (toUUID u) (mapMaybe extractSha shas) decodeExitCode :: Int -> ExitCode decodeExitCode 0 = ExitSuccess@@ -245,3 +262,6 @@ receivePackDoneAttr :: Name receivePackDoneAttr = "rpdone"++shasAttr :: Name+shasAttr = "shas"
@@ -27,36 +27,43 @@ } deriving (Read, Show) -connectXMPP :: XMPPCreds -> (JID -> XMPP a) -> IO (Either SomeException ())+connectXMPP :: XMPPCreds -> (JID -> XMPP a) -> IO [(HostPort, Either SomeException ())] connectXMPP c a = case parseJID (xmppJID c) of Nothing -> error "bad JID" Just jid -> connectXMPP' jid c a {- Do a SRV lookup, but if it fails, fall back to the cached xmppHostname. -}-connectXMPP' :: JID -> XMPPCreds -> (JID -> XMPP a) -> IO (Either SomeException ())-connectXMPP' jid c a = go =<< lookupSRV srvrecord+connectXMPP' :: JID -> XMPPCreds -> (JID -> XMPP a) -> IO [(HostPort, Either SomeException ())]+connectXMPP' jid c a = reverse <$> (go [] =<< lookupSRV srvrecord) where srvrecord = mkSRVTcp "xmpp-client" $ T.unpack $ strDomain $ jidDomain jid serverjid = JID Nothing (jidDomain jid) Nothing - go [] = run (xmppHostname c)- (PortNumber $ fromIntegral $ xmppPort c)- (a jid)- go ((h,p):rest) = do+ go l [] = do+ let h = xmppHostname c+ let p = PortNumber $ fromIntegral $ xmppPort c+ r <- run h p $ a jid+ return (r : l)+ go l ((h,p):rest) = do {- Try each SRV record in turn, until one connects, - at which point the MVar will be full. -} mv <- newEmptyMVar r <- run h p $ do liftIO $ putMVar mv () a jid- ifM (isEmptyMVar mv) (go rest, return r)+ ifM (isEmptyMVar mv)+ ( go (r : l) rest+ , return (r : l)+ ) {- Async exceptions are let through so the XMPP thread can - be killed. -}- run h p a' = tryNonAsync $- runClientError (Server serverjid h p) jid- (xmppUsername c) (xmppPassword c) (void a')+ run h p a' = do+ r <- tryNonAsync $+ runClientError (Server serverjid h p) jid+ (xmppUsername c) (xmppPassword c) (void a')+ return ((h, p), r) {- XMPP runClient, that throws errors rather than returning an Either -} runClientError :: Server -> JID -> T.Text -> T.Text -> XMPP a -> IO a
@@ -23,6 +23,7 @@ import Annex.UUID import Logs.UUID import Annex.TaggedPush+import Annex.CatFile import Config import Git import qualified Git.Branch@@ -43,6 +44,22 @@ import qualified Data.ByteString as B import qualified Data.Map as M +{- Largest chunk of data to send in a single XMPP message. -}+chunkSize :: Int+chunkSize = 4096++{- How long to wait for an expected message before assuming the other side+ - has gone away and canceling a push. + -+ - This needs to be long enough to allow a message of up to 2+ times+ - chunkSize to propigate up to a XMPP server, perhaps across to another+ - server, and back down to us. On the other hand, other XMPP pushes can be+ - delayed for running until the timeout is reached, so it should not be+ - excessive.+ -}+xmppTimeout :: Int+xmppTimeout = 120000000 -- 120 seconds+ finishXMPPPairing :: JID -> UUID -> Assistant () finishXMPPPairing jid u = void $ alertWhile alert $ makeXMPPGitRemote buddy (baseJID jid) u@@ -83,8 +100,8 @@ - - We listen at the other end of the pipe and relay to and from XMPP. -}-xmppPush :: ClientID -> (Git.Repo -> IO Bool) -> (NetMessage -> Assistant ()) -> Assistant Bool-xmppPush cid gitpush handledeferred = runPush SendPack cid handledeferred $ do+xmppPush :: ClientID -> (Git.Repo -> IO Bool) -> Assistant Bool+xmppPush cid gitpush = do u <- liftAnnex getUUID sendNetMessage $ Pushing cid (StartingPush u) @@ -120,7 +137,8 @@ liftIO $ do mapM_ killThread [t1, t2] mapM_ hClose [inh, outh, controlh]-+ mapM_ closeFd [Fd inf, Fd outf, Fd controlf]+ return r where toxmpp seqnum inh = do@@ -132,24 +150,26 @@ sendNetMessage $ Pushing cid $ SendPackOutput seqnum' b toxmpp seqnum' inh- fromxmpp outh controlh = forever $ do- m <- timeout xmppTimeout <~> waitNetPushMessage SendPack- case m of- (Just (Pushing _ (ReceivePackOutput _ b))) -> - liftIO $ writeChunk outh b- (Just (Pushing _ (ReceivePackDone exitcode))) ->- liftIO $ do- hPrint controlh exitcode- hFlush controlh- (Just _) -> noop- Nothing -> do- debug ["timeout waiting for git receive-pack output via XMPP"]- -- Send a synthetic exit code to git-annex- -- xmppgit, which will exit and cause git push- -- to die.- liftIO $ do- hPrint controlh (ExitFailure 1)- hFlush controlh+ + fromxmpp outh controlh = withPushMessagesInSequence cid SendPack handle+ where+ handle (Just (Pushing _ (ReceivePackOutput _ b))) = + liftIO $ writeChunk outh b+ handle (Just (Pushing _ (ReceivePackDone exitcode))) =+ liftIO $ do+ hPrint controlh exitcode+ hFlush controlh+ handle (Just _) = noop+ handle Nothing = do+ debug ["timeout waiting for git receive-pack output via XMPP"]+ -- Send a synthetic exit code to git-annex+ -- xmppgit, which will exit and cause git push+ -- to die.+ liftIO $ do+ hPrint controlh (ExitFailure 1)+ hFlush controlh+ killThread =<< myThreadId+ installwrapper tmpdir = liftIO $ do createDirectoryIfMissing True tmpdir let wrapper = tmpdir </> "git-remote-xmpp"@@ -159,6 +179,7 @@ , "exec " ++ program ++ " xmppgit" ] modifyFileMode wrapper $ addModes executeModes+ {- Use GIT_ANNEX_TMP_DIR if set, since that may be a better temp - dir (ie, not on a crippled filesystem where we can't make - the wrapper executable). -}@@ -169,7 +190,6 @@ tmp <- liftAnnex $ fromRepo gitAnnexTmpDir return $ tmp </> "xmppgit" Just d -> return $ d </> "xmppgit"- type EnvVar = String @@ -219,8 +239,8 @@ {- Relays git receive-pack stdin and stdout via XMPP, as well as propigating - its exit status to XMPP. -}-xmppReceivePack :: ClientID -> (NetMessage -> Assistant ()) -> Assistant Bool-xmppReceivePack cid handledeferred = runPush ReceivePack cid handledeferred $ do+xmppReceivePack :: ClientID -> Assistant Bool+xmppReceivePack cid = do repodir <- liftAnnex $ fromRepo repoPath let p = (proc "git" ["receive-pack", repodir]) { std_in = CreatePipe@@ -245,19 +265,17 @@ let seqnum' = succ seqnum sendNetMessage $ Pushing cid $ ReceivePackOutput seqnum' b relaytoxmpp seqnum' outh- relayfromxmpp inh = forever $ do- m <- timeout xmppTimeout <~> waitNetPushMessage ReceivePack- case m of- (Just (Pushing _ (SendPackOutput _ b))) ->- liftIO $ writeChunk inh b- (Just _) -> noop- Nothing -> do- debug ["timeout waiting for git send-pack output via XMPP"]- -- closing the handle will make- -- git receive-pack exit- liftIO $ do- hClose inh- killThread =<< myThreadId+ relayfromxmpp inh = withPushMessagesInSequence cid ReceivePack handle+ where+ handle (Just (Pushing _ (SendPackOutput _ b))) =+ liftIO $ writeChunk inh b+ handle (Just _) = noop+ handle Nothing = do+ debug ["timeout waiting for git send-pack output via XMPP"]+ -- closing the handle will make git receive-pack exit+ liftIO $ do+ hClose inh+ killThread =<< myThreadId xmppRemotes :: ClientID -> UUID -> Assistant [Remote] xmppRemotes cid theiruuid = case baseJID <$> parseJID cid of@@ -271,15 +289,12 @@ matching loc r = repoIsUrl r && repoLocation r == loc knownuuid um r = Remote.uuid r == theiruuid || M.member theiruuid um -handlePushInitiation :: (Remote -> Assistant ()) -> NetMessage -> Assistant ()-handlePushInitiation _ (Pushing cid (CanPush theiruuid)) =- unlessM (null <$> xmppRemotes cid theiruuid) $ do- u <- liftAnnex getUUID- sendNetMessage $ Pushing cid (PushRequest u)-handlePushInitiation checkcloudrepos (Pushing cid (PushRequest theiruuid)) =+{- Returns the ClientID that it pushed to. -}+runPush :: (Remote -> Assistant ()) -> NetMessage -> Assistant (Maybe ClientID)+runPush checkcloudrepos (Pushing cid (PushRequest theiruuid)) = go =<< liftAnnex (inRepo Git.Branch.current) where- go Nothing = noop+ go Nothing = return Nothing go (Just branch) = do rs <- xmppRemotes cid theiruuid liftAnnex $ Annex.Branch.commit "update"@@ -288,40 +303,79 @@ <*> getUUID liftIO $ Command.Sync.updateBranch (Command.Sync.syncBranch branch) g selfjid <- ((T.unpack <$>) . xmppClientID) <$> getDaemonStatus- forM_ rs $ \r -> do- void $ alertWhile (syncAlert [r]) $- xmppPush cid- (taggedPush u selfjid branch r)- (handleDeferred checkcloudrepos)- checkcloudrepos r-handlePushInitiation checkcloudrepos (Pushing cid (StartingPush theiruuid)) = do+ if null rs+ then return Nothing+ else do+ forM_ rs $ \r -> do+ void $ alertWhile (syncAlert [r]) $+ xmppPush cid (taggedPush u selfjid branch r)+ checkcloudrepos r+ return $ Just cid+runPush checkcloudrepos (Pushing cid (StartingPush theiruuid)) = do rs <- xmppRemotes cid theiruuid- unless (null rs) $ do- void $ alertWhile (syncAlert rs) $- xmppReceivePack cid (handleDeferred checkcloudrepos)- mapM_ checkcloudrepos rs-handlePushInitiation _ _ = noop+ if null rs+ then return Nothing+ else do+ void $ alertWhile (syncAlert rs) $+ xmppReceivePack cid+ mapM_ checkcloudrepos rs+ return $ Just cid+runPush _ _ = return Nothing -handleDeferred :: (Remote -> Assistant ()) -> NetMessage -> Assistant ()-handleDeferred = handlePushInitiation+{- Check if any of the shas that can be pushed are ones we do not+ - have.+ -+ - (Older clients send no shas, so when there are none, always+ - request a push.)+ -}+handlePushNotice :: NetMessage -> Assistant ()+handlePushNotice (Pushing cid (CanPush theiruuid shas)) =+ unlessM (null <$> xmppRemotes cid theiruuid) $+ if null shas+ then go+ else ifM (haveall shas)+ ( debug ["ignoring CanPush with known shas"]+ , go+ )+ where+ go = do+ u <- liftAnnex getUUID+ sendNetMessage $ Pushing cid (PushRequest u)+ haveall l = liftAnnex $ not <$> anyM donthave l+ donthave sha = isNothing <$> catObjectDetails sha+handlePushNotice _ = noop writeChunk :: Handle -> B.ByteString -> IO () writeChunk h b = do B.hPut h b hFlush h -{- Largest chunk of data to send in a single XMPP message. -}-chunkSize :: Int-chunkSize = 4096--{- How long to wait for an expected message before assuming the other side- - has gone away and canceling a push. +{- Gets NetMessages for a PushSide, ensures they are in order,+ - and runs an action to handle each in turn. The action will be passed+ - Nothing on timeout. -- - This needs to be long enough to allow a message of up to 2+ times- - chunkSize to propigate up to a XMPP server, perhaps across to another- - server, and back down to us. On the other hand, other XMPP pushes can be- - delayed for running until the timeout is reached, so it should not be- - excessive.+ - Does not currently reorder messages, but does ensure that any + - duplicate messages, or messages not in the sequence, are discarded. -}-xmppTimeout :: Int-xmppTimeout = 120000000 -- 120 seconds+withPushMessagesInSequence :: ClientID -> PushSide -> (Maybe NetMessage -> Assistant ()) -> Assistant ()+withPushMessagesInSequence cid side a = loop 0+ where+ loop seqnum = do+ m <- timeout xmppTimeout <~> waitInbox cid side+ let go s = a m >> loop s+ case extractSequence =<< m of+ Just seqnum'+ | seqnum' == seqnum + 1 -> go seqnum'+ | seqnum' == 0 -> go seqnum+ | seqnum' == seqnum -> do+ debug ["ignoring duplicate sequence number", show seqnum]+ loop seqnum+ | otherwise -> do+ debug ["ignoring out of order sequence number", show seqnum', "expected", show seqnum]+ loop seqnum+ Nothing -> go seqnum++extractSequence :: NetMessage -> Maybe Int+extractSequence (Pushing _ (ReceivePackOutput seqnum _)) = Just seqnum+extractSequence (Pushing _ (SendPackOutput seqnum _)) = Just seqnum+extractSequence _ = Nothing
binary file changed (53312 → 53312 bytes)
binary file changed (13604 → 13604 bytes)
binary file changed (2536 → 2536 bytes)
binary file changed (33088 → 33088 bytes)
@@ -1,3 +1,31 @@+git-annex (4.20130601) unstable; urgency=medium++ * XMPP: Git push over xmpp made much more robust.+ * XMPP: Avoid redundant and unncessary pushes. Note that this breaks+ compatibility with previous versions of git-annex, which will refuse+ to accept any XMPP pushes from this version.+ * XMPP: Send pings and use them to detect when contact with the server+ is lost.+ * hook special remote: Added combined hook program support.+ * Android app: Avoid using hard links to app's lib directory, which+ is sometimes on a different filesystem than the data directory.+ * Fix bug in parsing of parens in some preferred content expressions.+ This fixes the behavior of the manual mode group.+ * assistant: Work around git-cat-file's not reloading the index after files+ are staged.+ * Improve error handling when getting uuid of http remotes to auto-ignore,+ like with ssh remotes.+ * content: New command line way to view and configure a repository's+ preferred content settings.+ * sync: Fix double merge conflict resolution handling.+ * XMPP: Fix a file descriptor leak.+ * Android: Added an "Open WebApp" item to the terminal's menu.+ * Android: Work around Android devices where the `am` command doesn't work.+ * Can now restart certain long-running git processes if they crash, and+ continue working.++ -- Joey Hess <joeyh@debian.org> Sat, 01 Jun 2013 19:16:04 -0400+ git-annex (4.20130521) unstable; urgency=low * Sanitize debian changelog version before putting it into cabal file.
@@ -0,0 +1,48 @@+{- git-annex command+ -+ - Copyright 2013 Joey Hess <joey@kitenet.net>+ -+ - Licensed under the GNU GPL version 3 or higher.+ -}++module Command.Content where++import Common.Annex+import Command+import qualified Remote+import Logs.PreferredContent++import qualified Data.Map as M++def :: [Command]+def = [command "content" (paramPair paramRemote (paramOptional paramExpression)) seek+ SectionSetup "get or set preferred content expression"]++seek :: [CommandSeek]+seek = [withWords start]++start :: [String] -> CommandStart+start = parse+ where+ parse (name:[]) = go name performGet+ parse (name:expr:[]) = go name $ \uuid -> do+ showStart "content" name+ performSet expr uuid+ parse _ = error "Specify a repository."++ go name a = do+ u <- Remote.nameToUUID name+ next $ a u++performGet :: UUID -> CommandPerform+performGet uuid = do+ m <- preferredContentMapRaw+ liftIO $ putStrLn $ fromMaybe "" $ M.lookup uuid m+ next $ return True++performSet :: String -> UUID -> CommandPerform+performSet expr uuid = case checkPreferredContentExpression expr of+ Just e -> error $ "Parse error: " ++ e+ Nothing -> do+ preferredContentSet uuid expr+ next $ return True
@@ -0,0 +1,288 @@+{- git-annex fuzz generator+ -+ - Copyright 2013 Joey Hess <joey@kitenet.net>+ -+ - Licensed under the GNU GPL version 3 or higher.+ -}++module Command.FuzzTest where++import Common.Annex+import qualified Annex+import Command+import qualified Git.Config+import Config+import Utility.ThreadScheduler+import Annex.Exception+import Utility.DiskFree++import Data.Time.Clock+import System.Random (getStdRandom, random, randomR)+import Test.QuickCheck+import Control.Concurrent++def :: [Command]+def = [ notBareRepo $ command "fuzztest" paramNothing seek SectionPlumbing+ "generates fuzz test files"]++seek :: [CommandSeek]+seek = [withNothing start]++start :: CommandStart+start = do+ guardTest+ logf <- fromRepo gitAnnexFuzzTestLogFile+ showStart "fuzztest" logf+ logh <-liftIO $ openFile logf WriteMode+ void $ forever $ fuzz logh+ stop++guardTest :: Annex ()+guardTest = unlessM (fromMaybe False . Git.Config.isTrue <$> getConfig key "") $+ error $ unlines+ [ "Running fuzz tests *writes* to and *deletes* files in"+ , "this repository, and pushes those changes to other"+ , "repositories! This is a developer tool, not something"+ , "to play with."+ , ""+ , "Refusing to run fuzz tests, since " ++ keyname ++ " is not set!"+ ]+ where+ key = annexConfig "eat-my-repository"+ (ConfigKey keyname) = key+++fuzz :: Handle -> Annex ()+fuzz logh = do+ action <- genFuzzAction+ record logh $ flip Started action+ result <- tryAnnex $ runFuzzAction action+ record logh $ flip Finished $+ either (const False) (const True) result++record :: Handle -> (UTCTime -> TimeStampedFuzzAction) -> Annex ()+record h tmpl = liftIO $ do+ now <- getCurrentTime+ let s = show $ tmpl now+ print s+ hPrint h s+ hFlush h++{- Delay for either a fraction of a second, or a few seconds, or up+ - to 1 minute.+ -+ - The MinutesDelay is used as an opportunity to do housekeeping tasks.+ -}+randomDelay :: Delay -> Annex ()+randomDelay TinyDelay = liftIO $+ threadDelay =<< getStdRandom (randomR (10000, 1000000))+randomDelay SecondsDelay = liftIO $ + threadDelaySeconds =<< Seconds <$> getStdRandom (randomR (1, 10))+randomDelay MinutesDelay = do+ liftIO $ threadDelaySeconds =<< Seconds <$> getStdRandom (randomR (1, 60))+ reserve <- annexDiskReserve <$> Annex.getGitConfig+ free <- liftIO $ getDiskFree "."+ case free of+ Just have | have < reserve -> do+ warning "Low disk space; fuzz test paused."+ liftIO $ threadDelaySeconds (Seconds 60)+ randomDelay MinutesDelay+ _ -> noop++data Delay+ = TinyDelay+ | SecondsDelay+ | MinutesDelay+ deriving (Read, Show, Eq)++instance Arbitrary Delay where+ arbitrary = elements [TinyDelay, SecondsDelay, MinutesDelay]++data FuzzFile = FuzzFile FilePath+ deriving (Read, Show, Eq)++data FuzzDir = FuzzDir FilePath+ deriving (Read, Show, Eq)++instance Arbitrary FuzzFile where+ arbitrary = FuzzFile <$> arbitrary++instance Arbitrary FuzzDir where+ arbitrary = FuzzDir <$> arbitrary++class ToFilePath a where+ toFilePath :: a -> FilePath++instance ToFilePath FuzzFile where+ toFilePath (FuzzFile f) = f++instance ToFilePath FuzzDir where+ toFilePath (FuzzDir d) = d++isFuzzFile :: FilePath -> Bool+isFuzzFile f = "fuzzfile_" `isPrefixOf` takeFileName f++isFuzzDir :: FilePath -> Bool+isFuzzDir d = "fuzzdir_" `isPrefixOf` d++mkFuzzFile :: FilePath -> [FuzzDir] -> FuzzFile+mkFuzzFile file dirs = FuzzFile $ joinPath (map toFilePath dirs) </> ("fuzzfile_" ++ file)++mkFuzzDir :: Int -> FuzzDir+mkFuzzDir n = FuzzDir $ "fuzzdir_" ++ show n++{- File is placed inside a directory hierarchy up to 4 subdirectories deep. -}+genFuzzFile :: IO FuzzFile+genFuzzFile = do+ n <- getStdRandom $ randomR (0, 4)+ dirs <- replicateM n genFuzzDir+ file <- show <$> (getStdRandom random :: IO Int)+ return $ mkFuzzFile file dirs++{- Only 16 distinct subdirectories are used. When nested 4 deep, this+ - yields 69904 total directories max, which is below the default Linux+ - inotify limit of 81920. The goal is not to run the assistant out of+ - inotify descriptors. -}+genFuzzDir :: IO FuzzDir+genFuzzDir = mkFuzzDir <$> (getStdRandom (randomR (1,16)) :: IO Int)++localFile :: FilePath -> Bool+localFile f+ | isAbsolute f = False+ | ".." `isInfixOf` f = False+ | ".git" `isPrefixOf` f = False+ | otherwise = True++data TimeStampedFuzzAction + = Started UTCTime FuzzAction+ | Finished UTCTime Bool+ deriving (Read, Show)++data FuzzAction+ = FuzzAdd FuzzFile+ | FuzzDelete FuzzFile+ | FuzzMove FuzzFile FuzzFile+ | FuzzModify FuzzFile+ | FuzzDeleteDir FuzzDir+ | FuzzMoveDir FuzzDir FuzzDir+ | FuzzPause Delay+ deriving (Read, Show, Eq)++instance Arbitrary FuzzAction where+ arbitrary = frequency+ [ (50, FuzzAdd <$> arbitrary)+ , (50, FuzzDelete <$> arbitrary)+ , (10, FuzzMove <$> arbitrary <*> arbitrary)+ , (10, FuzzModify <$> arbitrary)+ , (10, FuzzDeleteDir <$> arbitrary)+ , (10, FuzzMoveDir <$> arbitrary <*> arbitrary)+ , (10, FuzzPause <$> arbitrary)+ ]++runFuzzAction :: FuzzAction -> Annex ()+runFuzzAction (FuzzAdd (FuzzFile f)) = liftIO $ do+ createDirectoryIfMissing True $ parentDir f+ n <- getStdRandom random :: IO Int+ writeFile f $ show n ++ "\n"+runFuzzAction (FuzzDelete (FuzzFile f)) = liftIO $ nukeFile f+runFuzzAction (FuzzMove (FuzzFile src) (FuzzFile dest)) = liftIO $+ rename src dest+runFuzzAction (FuzzModify (FuzzFile f)) = whenM isDirect $ liftIO $ do+ n <- getStdRandom random :: IO Int+ appendFile f $ show n ++ "\n"+runFuzzAction (FuzzDeleteDir (FuzzDir d)) = liftIO $+ removeDirectoryRecursive d+runFuzzAction (FuzzMoveDir (FuzzDir src) (FuzzDir dest)) = liftIO $+ rename src dest+runFuzzAction (FuzzPause d) = randomDelay d++genFuzzAction :: Annex FuzzAction+genFuzzAction = do+ tmpl <- liftIO $ Prelude.head <$> sample' (arbitrary :: Gen FuzzAction)+ -- Fix up template action to make sense in the current repo tree.+ case tmpl of+ FuzzAdd _ -> do+ f <- liftIO newFile+ maybe genFuzzAction (return . FuzzAdd) f+ FuzzDelete _ -> do+ f <- liftIO $ existingFile 0 ""+ maybe genFuzzAction (return . FuzzDelete) f+ FuzzMove _ _ -> do+ src <- liftIO $ existingFile 0 ""+ dest <- liftIO newFile+ case (src, dest) of+ (Just s, Just d) -> return $ FuzzMove s d+ _ -> genFuzzAction+ FuzzMoveDir _ _ -> do+ md <- liftIO existingDir+ case md of+ Nothing -> genFuzzAction+ Just d -> do+ newd <- liftIO $ newDir (parentDir $ toFilePath d)+ maybe genFuzzAction (return . FuzzMoveDir d) newd+ FuzzDeleteDir _ -> do+ d <- liftIO existingDir+ maybe genFuzzAction (return . FuzzDeleteDir) d+ FuzzModify _ -> do+ f <- liftIO $ existingFile 0 ""+ maybe genFuzzAction (return . FuzzModify) f+ FuzzPause _ -> return tmpl++existingFile :: Int -> FilePath -> IO (Maybe FuzzFile)+existingFile 0 _ = return Nothing+existingFile n top = do+ dir <- existingDirIncludingTop+ contents <- catchDefaultIO [] (getDirectoryContents dir)+ let files = filter isFuzzFile contents+ if null files+ then do+ let dirs = filter isFuzzDir contents+ if null dirs+ then return Nothing+ else do+ i <- getStdRandom $ randomR (0, length dirs - 1)+ existingFile (n - 1) (top </> dirs !! i)+ else do+ i <- getStdRandom $ randomR (0, length files - 1)+ return $ Just $ FuzzFile $ top </> dir </> files !! i++existingDirIncludingTop :: IO FilePath+existingDirIncludingTop = do+ dirs <- filter isFuzzDir <$> getDirectoryContents "."+ if null dirs+ then return "."+ else do+ n <- getStdRandom $ randomR (0, length dirs)+ return $ ("." : dirs) !! n++existingDir :: IO (Maybe FuzzDir)+existingDir = do+ d <- existingDirIncludingTop+ return $ if isFuzzDir d+ then Just $ FuzzDir d+ else Nothing++newFile :: IO (Maybe FuzzFile)+newFile = go (100 :: Int)+ where+ go 0 = return Nothing+ go n = do+ f <- genFuzzFile+ ifM (doesnotexist (toFilePath f))+ ( return $ Just f+ , go (n - 1)+ )++newDir :: FilePath -> IO (Maybe FuzzDir)+newDir parent = go (100 :: Int)+ where+ go 0 = return Nothing+ go n = do+ (FuzzDir d) <- genFuzzDir+ ifM (doesnotexist (parent </> d))+ ( return $ Just $ FuzzDir d+ , go (n - 1)+ )++doesnotexist :: FilePath -> IO Bool+doesnotexist f = isNothing <$> catchMaybeIO (getSymbolicLinkStatus f)
@@ -17,7 +17,7 @@ def :: [Command] def = [command "group" (paramPair paramRemote paramDesc) seek- SectionCommon "add a repository to a group"]+ SectionSetup "add a repository to a group"] seek :: [CommandSeek] seek = [withWords start]
@@ -35,6 +35,7 @@ import Utility.Percentage import Logs.Transfer import Types.TrustLevel+import Types.FileMatcher import qualified Limit -- a named computation that produces a statistic@@ -286,7 +287,7 @@ where initial = (emptyKeyData, emptyKeyData) update matcher key file vs@(presentdata, referenceddata) =- ifM (matcher $ Annex.FileInfo file file)+ ifM (matcher $ FileInfo file file) ( (,) <$> ifM (inAnnex key) ( return $ addKey key presentdata
@@ -28,6 +28,7 @@ import qualified Remote.Git import Types.Key import Config+import Annex.ReplaceFile import Data.Hash.MD5 @@ -247,8 +248,13 @@ resolveMerge' u | issymlink LsFiles.valUs && issymlink LsFiles.valThem = withKey LsFiles.valUs $ \keyUs ->- withKey LsFiles.valThem $ \keyThem -> do- go keyUs keyThem+ withKey LsFiles.valThem $ \keyThem -> do+ ifM isDirect+ ( maybe noop (\k -> removeDirect k file) keyUs+ , liftIO $ nukeFile file+ )+ Annex.Queue.addCommand "rm" [Params "--quiet -f --"] [file]+ go keyUs keyThem | otherwise = return False where go keyUs keyThem@@ -256,11 +262,6 @@ makelink keyUs return True | otherwise = do- ifM isDirect- ( maybe noop (\k -> removeDirect k file) keyUs- , liftIO $ nukeFile file- )- Annex.Queue.addCommand "rm" [Params "--quiet -f --"] [file] makelink keyUs makelink keyThem return True@@ -270,8 +271,8 @@ makelink (Just key) = do let dest = mergeFile file key l <- inRepo $ gitAnnexLink dest key- liftIO $ nukeFile dest- addAnnexLink l dest+ replaceFile dest $ makeAnnexLink l+ stageSymlink dest =<< hashSymlink l whenM (isDirect) $ toDirect key dest makelink _ = noop@@ -302,7 +303,7 @@ | otherwise = go $ shortHash $ key2file key where varmarker = ".variant-"- doubleconflict = varmarker `isSuffixOf` (dropExtension file)+ doubleconflict = varmarker `isInfixOf` file go v = takeDirectory file </> dropExtension (takeFileName file) ++ varmarker ++ v
@@ -21,6 +21,7 @@ import Logs.Trust import Logs.Group import Logs.PreferredContent+import Types.StandardGroups import Remote def :: [Command]@@ -94,27 +95,30 @@ trust = settings cfgTrustMap [ "" , com "Repository trust configuration"- , com "(Valid trust levels: " ++- unwords (map showTrustLevel [Trusted .. DeadTrusted]) ++- ")"+ , com "(Valid trust levels: " ++ trustlevels ++ ")" ] (\(t, u) -> line "trust" u $ showTrustLevel t) (\u -> lcom $ line "trust" u $ showTrustLevel SemiTrusted)+ where+ trustlevels = unwords $ map showTrustLevel [Trusted .. DeadTrusted] groups = settings cfgGroupMap [ "" , com "Repository groups"+ , com $ "(Standard groups: " ++ grouplist ++ ")" , com "(Separate group names with spaces)" ] (\(s, u) -> line "group" u $ unwords $ S.toList s) (\u -> lcom $ line "group" u "")+ where+ grouplist = unwords $ map fromStandardGroup [minBound..] preferredcontent = settings cfgPreferredContentMap [ "" , com "Repository preferred contents" ]- (\(s, u) -> line "preferred-content" u s)- (\u -> line "preferred-content" u "")+ (\(s, u) -> line "content" u s)+ (\u -> line "content" u "") settings field desc showvals showdefaults = concat [ desc@@ -163,7 +167,7 @@ | setting == "group" = let m = M.insert u (S.fromList $ words value) (cfgGroupMap cfg) in Right $ cfg { cfgGroupMap = m }- | setting == "preferred-content" = + | setting == "content" = case checkPreferredContentExpression value of Just e -> Left e Nothing ->
@@ -20,6 +20,7 @@ import Annex.Environment import Utility.WebApp import Utility.Daemon (checkDaemon)+import Utility.Env import Init import qualified Git import qualified Git.Config@@ -32,7 +33,7 @@ import Control.Concurrent.STM import System.Process (env, std_out, std_err) import Network.Socket (HostName)-import System.Environment+import System.Environment (getArgs) def :: [Command] def = [ withOptions [listenOption] $@@ -157,22 +158,23 @@ sendurlback v _origout _origerr url _htmlshim = putMVar v url openBrowser :: Maybe FilePath -> FilePath -> String -> Maybe Handle -> Maybe Handle -> IO ()-#ifdef __ANDROID__-openBrowser mcmd htmlshim realurl outh errh = do+#ifndef __ANDROID__+openBrowser mcmd htmlshim _realurl outh errh = runbrowser #else-openBrowser mcmd htmlshim _realurl outh errh = do+openBrowser mcmd htmlshim realurl outh errh = do+ {- The Android app has a menu item that opens this file. -}+ writeFile "/sdcard/git-annex.home/.git-annex-url" url+ {- Android's `am` command does not work reliably across the+ - wide range of Android devices. Intead, FIFO should be set to + - the filename of a fifo that we can write the URL to. -}+ v <- getEnv "FIFO"+ case v of+ Nothing -> runbrowser+ Just f -> void $ forkIO $ do+ fd <- openFd f WriteOnly Nothing defaultFileFlags+ void $ fdWrite fd url+ closeFd fd #endif- hPutStrLn (fromMaybe stdout outh) $ "Launching web browser on " ++ url- hFlush stdout- environ <- cleanEnvironment- (_, _, _, pid) <- createProcess p- { env = environ- , std_out = maybe Inherit UseHandle outh- , std_err = maybe Inherit UseHandle errh- }- exitcode <- waitForProcess pid- unless (exitcode == ExitSuccess) $- hPutStrLn (fromMaybe stderr errh) "failed to start web browser" where p = case mcmd of Just cmd -> proc cmd [htmlshim]@@ -185,6 +187,18 @@ #else url = fileUrl htmlshim #endif+ runbrowser = do+ hPutStrLn (fromMaybe stdout outh) $ "Launching web browser on " ++ url+ hFlush stdout+ environ <- cleanEnvironment+ (_, _, _, pid) <- createProcess p+ { env = environ+ , std_out = maybe Inherit UseHandle outh+ , std_err = maybe Inherit UseHandle errh+ }+ exitcode <- waitForProcess pid+ unless (exitcode == ExitSuccess) $ do+ hPutStrLn (fromMaybe stderr errh) "failed to start web browser" {- web.browser is a generic git config setting for a web browser program -} webBrowser :: Git.Repo -> Maybe FilePath
binary file changed (15108 → 15108 bytes)
@@ -13,6 +13,7 @@ import Git import Git.Sha import Git.Command+import Git.Ref (headRef) {- The currently checked out branch. -@@ -35,7 +36,7 @@ {- The current branch, which may not really exist yet. -} currentUnsafe :: Repo -> IO (Maybe Git.Ref) currentUnsafe r = parse . firstLine- <$> pipeReadStrict [Param "symbolic-ref", Param "HEAD"] r+ <$> pipeReadStrict [Param "symbolic-ref", Param $ show headRef] r where parse l | null l = Nothing
@@ -29,7 +29,7 @@ type CatFileHandle = CoProcess.CoProcessHandle catFileStart :: Repo -> IO CatFileHandle-catFileStart = CoProcess.rawMode <=< gitCoProcessStart+catFileStart = CoProcess.rawMode <=< gitCoProcessStart True [ Param "cat-file" , Param "--batch" ]
@@ -22,7 +22,7 @@ checkAttrStart :: [Attr] -> Repo -> IO CheckAttrHandle checkAttrStart attrs repo = do cwd <- getCurrentDirectory- h <- CoProcess.rawMode =<< gitCoProcessStart params repo+ h <- CoProcess.rawMode =<< gitCoProcessStart True params repo return (h, attrs, cwd) where params =
@@ -109,8 +109,10 @@ leaveZombie = fst {- Runs a git command as a coprocess. -}-gitCoProcessStart :: [CommandParam] -> Repo -> IO CoProcess.CoProcessHandle-gitCoProcessStart params repo = CoProcess.start "git" (toCommand $ gitCommandLine params repo) (gitEnv repo)+gitCoProcessStart :: Bool -> [CommandParam] -> Repo -> IO CoProcess.CoProcessHandle+gitCoProcessStart restartable params repo = CoProcess.start restartable "git"+ (toCommand $ gitCommandLine params repo)+ (gitEnv repo) gitCreateProcess :: [CommandParam] -> Repo -> CreateProcess gitCreateProcess params repo =
@@ -46,7 +46,10 @@ diffIndex :: Repo -> IO ([DiffTreeItem], IO Bool) diffIndex repo = do ifM (Git.Ref.headExists repo)- ( getdiff (Param "diff-index") [Param "--cached", Param "HEAD"] repo+ ( getdiff (Param "diff-index")+ [ Param "--cached"+ , Param $ show Git.Ref.headRef+ ] repo , return ([], return True) )
@@ -17,7 +17,7 @@ type HashObjectHandle = CoProcess.CoProcessHandle hashObjectStart :: Repo -> IO HashObjectHandle-hashObjectStart = CoProcess.rawMode <=< gitCoProcessStart+hashObjectStart = CoProcess.rawMode <=< gitCoProcessStart True [ Param "hash-object" , Param "-w" , Param "--stdin-paths"
@@ -1,6 +1,6 @@ {- git ref stuff -- - Copyright 2011 Joey Hess <joey@kitenet.net>+ - Copyright 2011-2013 Joey Hess <joey@kitenet.net> - - Licensed under the GNU GPL version 3 or higher. -}@@ -13,6 +13,9 @@ import Data.Char (chr) +headRef :: Ref+headRef = Ref "HEAD"+ {- Converts a fully qualified git ref into a user-visible string. -} describe :: Ref -> String describe = show . base@@ -54,18 +57,26 @@ process [] = Nothing process s = Just $ Ref $ firstLine s -{- List of (refs, branches) matching a given ref spec. -}-matching :: Ref -> Repo -> IO [(Ref, Branch)]-matching ref repo = map gen . lines <$> - pipeReadStrict [Param "show-ref", Param $ show ref] repo+{- List of (shas, branches) matching a given ref or refs. -}+matching :: [Ref] -> Repo -> IO [(Sha, Branch)]+matching refs repo = matching' (map show refs) repo++{- Includes HEAD in the output, if asked for it. -}+matchingWithHEAD :: [Ref] -> Repo -> IO [(Sha, Branch)]+matchingWithHEAD refs repo = matching' ("--head" : map show refs) repo++{- List of (shas, branches) matching a given ref or refs. -}+matching' :: [String] -> Repo -> IO [(Sha, Branch)]+matching' ps repo = map gen . lines <$> + pipeReadStrict (Param "show-ref" : map Param ps) repo where gen l = let (r, b) = separate (== ' ') l in (Ref r, Ref b) -{- List of (refs, branches) matching a given ref spec.- - Duplicate refs are filtered out. -}-matchingUniq :: Ref -> Repo -> IO [(Ref, Branch)]-matchingUniq ref repo = nubBy uniqref <$> matching ref repo+{- List of (shas, branches) matching a given ref spec.+ - Duplicate shas are filtered out. -}+matchingUniq :: [Ref] -> Repo -> IO [(Sha, Branch)]+matchingUniq refs repo = nubBy uniqref <$> matching refs repo where uniqref (a, _) (b, _) = a == b
@@ -41,7 +41,7 @@ {- A git ref. Can be a sha1, or a branch or tag name. -} newtype Ref = Ref String- deriving (Eq)+ deriving (Eq, Ord) instance Show Ref where show (Ref v) = v
@@ -52,6 +52,7 @@ import qualified Command.Semitrust import qualified Command.Dead import qualified Command.Group+import qualified Command.Content import qualified Command.Ungroup import qualified Command.Vicfg import qualified Command.Sync@@ -75,9 +76,8 @@ #endif #endif #ifdef WITH_TESTSUITE-#ifndef __WINDOWS__ import qualified Command.Test-#endif+import qualified Command.FuzzTest #endif cmds :: [Command]@@ -106,6 +106,7 @@ , Command.Semitrust.def , Command.Dead.def , Command.Group.def+ , Command.Content.def , Command.Ungroup.def , Command.Vicfg.def , Command.FromKey.def@@ -143,9 +144,8 @@ #endif #endif #ifdef WITH_TESTSUITE-#ifndef __WINDOWS__ , Command.Test.def-#endif+ , Command.FuzzTest.def #endif ]
@@ -13,12 +13,6 @@ import qualified Data.Set as S import qualified Data.Map as M import System.Path.WildMatch-#ifdef WITH_TDFA-import Text.Regex.TDFA-import Text.Regex.TDFA.String-#else-import System.Path.WildMatch-#endif import System.PosixCompat.Files import Common.Annex@@ -32,11 +26,20 @@ import Types.TrustLevel import Types.Key import Types.Group+import Types.FileMatcher import Logs.Group import Utility.HumanTime import Utility.DataUnits -type MatchFiles = AssumeNotPresent -> Annex.FileInfo -> Annex Bool+#ifdef WITH_TDFA+import Text.Regex.TDFA+import Text.Regex.TDFA.String+#else+import System.Path.WildMatch+import Types.FileMatcher+#endif++type MatchFiles = AssumeNotPresent -> FileInfo -> Annex Bool type MkLimit = String -> Either String MatchFiles type AssumeNotPresent = S.Set UUID @@ -46,10 +49,10 @@ {- Gets a matcher for the user-specified limits. The matcher is cached for - speed; once it's obtained the user-specified limits can't change. -}-getMatcher :: Annex (Annex.FileInfo -> Annex Bool)+getMatcher :: Annex (FileInfo -> Annex Bool) getMatcher = Utility.Matcher.matchM <$> getMatcher' -getMatcher' :: Annex (Utility.Matcher.Matcher (Annex.FileInfo -> Annex Bool))+getMatcher' :: Annex (Utility.Matcher.Matcher (FileInfo -> Annex Bool)) getMatcher' = do m <- Annex.getState Annex.limit case m of@@ -61,7 +64,7 @@ return matcher {- Adds something to the limit list, which is built up reversed. -}-add :: Utility.Matcher.Token (Annex.FileInfo -> Annex Bool) -> Annex ()+add :: Utility.Matcher.Token (FileInfo -> Annex Bool) -> Annex () add l = Annex.changeState $ \s -> s { Annex.limit = prepend $ Annex.limit s } where prepend (Left ls) = Left $ l:ls@@ -92,11 +95,11 @@ {- Could just use wildCheckCase, but this way the regex is only compiled - once. Also, we use regex-TDFA when available, because it's less buggy - in its support of non-unicode characters. -}-matchglob :: String -> Annex.FileInfo -> Bool+matchglob :: String -> FileInfo -> Bool matchglob glob fi = #ifdef WITH_TDFA case cregex of- Right r -> case execute r (Annex.matchFile fi) of+ Right r -> case execute r (matchFile fi) of Right (Just _) -> True _ -> False Left _ -> error $ "failed to compile regex: " ++ regex@@ -104,7 +107,7 @@ cregex = compile defaultCompOpt defaultExecOpt regex regex = '^':wildToRegex glob #else- wildCheckCase glob (Annex.matchFile fi)+ wildCheckCase glob (matchFile fi) #endif {- Adds a limit to skip files not believed to be present@@ -150,7 +153,7 @@ {- Limit to content that is in a directory, anywhere in the repository tree -} limitInDir :: FilePath -> MkLimit limitInDir dir = const $ Right $ const $ \fi -> return $- any (== dir) $ splitPath $ takeDirectory $ Annex.matchFile fi+ any (== dir) $ splitPath $ takeDirectory $ matchFile fi {- Adds a limit to skip files not believed to have the specified number - of copies. -}@@ -228,7 +231,7 @@ check fi sz Nothing = do filesize <- liftIO $ catchMaybeIO $ fromIntegral . fileSize- <$> getFileStatus (Annex.relFile fi)+ <$> getFileStatus (relFile fi) return $ filesize `vs` Just sz addTimeLimit :: String -> Annex ()@@ -244,5 +247,5 @@ liftIO $ exitWith $ ExitFailure 101 else return True -lookupFile :: Annex.FileInfo -> Annex (Maybe (Key, Backend))-lookupFile = Backend.lookupFile . Annex.relFile+lookupFile :: FileInfo -> Annex (Maybe (Key, Backend))+lookupFile = Backend.lookupFile . relFile
@@ -36,6 +36,7 @@ gitAnnexPidFile, gitAnnexDaemonStatusFile, gitAnnexLogFile,+ gitAnnexFuzzTestLogFile, gitAnnexHtmlShim, gitAnnexUrlFile, gitAnnexTmpCfgFile,@@ -226,6 +227,10 @@ {- Log file for daemon mode. -} gitAnnexLogFile :: Git.Repo -> FilePath gitAnnexLogFile r = gitAnnexDir r </> "daemon.log"++{- Log file for fuzz test. -}+gitAnnexFuzzTestLogFile :: Git.Repo -> FilePath+gitAnnexFuzzTestLogFile r = gitAnnexDir r </> "fuzztest.log" {- Html shim file used to launch the webapp. -} gitAnnexHtmlShim :: Git.Repo -> FilePath
@@ -119,7 +119,7 @@ mode <- annexFileMode fd <- liftIO $ prep tfile mode info ok <- retry info metervar $- bracketIO (return fd) (cleanup tfile) (a meter)+ bracketIO (return fd) (cleanup tfile) (const $ a meter) unless ok $ recordFailedTransfer t info return ok where
@@ -141,7 +141,7 @@ tryGitConfigRead r | haveconfig r = return r -- already read | Git.repoIsSsh r = store $ do- v <- onRemote r (pipedsshconfig, Left undefined) "configlist" [] []+ v <- onRemote r (pipedconfig, Left undefined) "configlist" [] [] case v of Right r' | haveconfig r' -> return r'@@ -149,7 +149,7 @@ Left _ -> configlist_failed | Git.repoIsHttp r = do headers <- getHttpHeaders- store $ safely $ geturlconfig headers+ store $ geturlconfig headers | Git.repoIsUrl r = return r | otherwise = store $ safely $ onLocal r $ do ensureInitialized@@ -162,8 +162,9 @@ safely a = either (const $ return r) return =<< liftIO (try a :: IO (Either SomeException Git.Repo)) - pipedconfig cmd params =- withHandle StdoutHandle createProcessSuccess p $ \h -> do+ pipedconfig cmd params = try run :: IO (Either SomeException Git.Repo)+ where+ run = withHandle StdoutHandle createProcessSuccess p $ \h -> do fileEncoding h val <- hGetContentsStrict h r' <- Git.Config.store val r@@ -172,18 +173,20 @@ warningIO $ "Instead, got: " ++ show val warningIO $ "This is unexpected; please check the network transport!" return r'- where p = proc cmd $ toCommand params - pipedsshconfig cmd params =- liftIO (try (pipedconfig cmd params) :: IO (Either SomeException Git.Repo))- geturlconfig headers = do- s <- Url.get (Git.repoLocation r ++ "/config") headers- withTmpFile "git-annex.tmp" $ \tmpfile h -> do- hPutStr h s+ v <- liftIO $ withTmpFile "git-annex.tmp" $ \tmpfile h -> do hClose h- safely $ pipedconfig "git" [Param "config", Param "--null", Param "--list", Param "--file", File tmpfile]+ ifM (Url.downloadQuiet (Git.repoLocation r ++ "/config") headers [] tmpfile)+ ( pipedconfig "git" [Param "config", Param "--null", Param "--list", Param "--file", File tmpfile]+ , return $ Left undefined+ )+ case v of+ Left _ -> do+ set_ignore "not usable by git-annex"+ return r+ Right r' -> return r' store = observe $ \r' -> do g <- gitRepo@@ -204,11 +207,16 @@ configlist_failed = case Git.remoteName r of Nothing -> return r Just n -> do- whenM (inRepo $ Git.Command.runBool [Param "fetch", Param "--quiet", Param n]) $ do- let k = "remote." ++ n ++ ".annex-ignore"- warning $ "Remote " ++ n ++ " does not have git-annex installed; setting " ++ k- inRepo $ Git.Command.run [Param "config", Param k, Param "true"]+ whenM (inRepo $ Git.Command.runBool [Param "fetch", Param "--quiet", Param n]) $+ set_ignore $ "does not have git-annex installed" return r+ + set_ignore msg = case Git.remoteName r of+ Nothing -> noop+ Just n -> do+ let k = "remote." ++ n ++ ".annex-ignore"+ warning $ "Remote " ++ n ++ " " ++ msg ++ "; setting " ++ k+ inRepo $ Git.Command.run [Param "config", Param k, Param "true"] {- Checks if a given remote has the content for a key inAnnex. - If the remote cannot be accessed, or if it cannot determine@@ -346,7 +354,7 @@ forever $ send =<< readSV v let feeder = writeSV v . fromBytesProcessed- bracketIO noop (const $ tryIO $ killThread tid) (a feeder)+ bracketIO noop (const $ tryIO $ killThread tid) (const $ a feeder) copyFromRemoteCheap :: Remote -> Key -> FilePath -> Annex Bool copyFromRemoteCheap r key file
@@ -23,6 +23,9 @@ import Crypto import Utility.Metered +type Action = String+type HookName = String+ remote :: RemoteType remote = RemoteType { typename = "hook",@@ -67,14 +70,15 @@ gitConfigSpecialRemote u c' "hooktype" hooktype return c' -hookEnv :: Key -> Maybe FilePath -> IO (Maybe [(String, String)])-hookEnv k f = Just <$> mergeenv (fileenv f ++ keyenv)+hookEnv :: Action -> Key -> Maybe FilePath -> IO (Maybe [(String, String)])+hookEnv action k f = Just <$> mergeenv (fileenv f ++ keyenv) where mergeenv l = M.toList . M.union (M.fromList l) <$> M.fromList <$> getEnvironment env s v = ("ANNEX_" ++ s, v) keyenv = catMaybes [ Just $ env "KEY" (key2file k)+ , Just $ env "ACTION" action , env "HASH_1" <$> headMaybe hashbits , env "HASH_2" <$> headMaybe (drop 1 hashbits) ]@@ -82,64 +86,70 @@ fileenv (Just file) = [env "FILE" file] hashbits = map takeDirectory $ splitPath $ hashDirMixed k -lookupHook :: String -> String -> Annex (Maybe String)-lookupHook hooktype hook =do- command <- getConfig (annexConfig hookname) ""+lookupHook :: HookName -> Action -> Annex (Maybe String)+lookupHook hookname action = do+ command <- getConfig (annexConfig hook) "" if null command then do- warning $ "missing configuration for " ++ hookname- return Nothing+ fallback <- getConfig (annexConfig $ hookfallback) ""+ if null fallback+ then do+ warning $ "missing configuration for " ++ hook ++ " or " ++ hookfallback+ return Nothing+ else return $ Just fallback else return $ Just command where- hookname = hooktype ++ "-" ++ hook ++ "-hook"+ hook = hookname ++ "-" ++ action ++ "-hook"+ hookfallback = hookname ++ "-hook" -runHook :: String -> String -> Key -> Maybe FilePath -> Annex Bool -> Annex Bool-runHook hooktype hook k f a = maybe (return False) run =<< lookupHook hooktype hook+runHook :: HookName -> Action -> Key -> Maybe FilePath -> Annex Bool -> Annex Bool+runHook hook action k f a = maybe (return False) run =<< lookupHook hook action where run command = do showOutput -- make way for hook output- ifM (liftIO $ boolSystemEnv "sh" [Param "-c", Param command] =<< hookEnv k f)+ ifM (liftIO $ boolSystemEnv "sh" [Param "-c", Param command] =<< hookEnv action k f) ( a , do warning $ hook ++ " hook exited nonzero!" return False ) -store :: String -> Key -> AssociatedFile -> MeterUpdate -> Annex Bool+store :: HookName -> Key -> AssociatedFile -> MeterUpdate -> Annex Bool store h k _f _p = sendAnnex k (void $ remove h k) $ \src -> runHook h "store" k (Just src) $ return True -storeEncrypted :: String -> GpgOpts -> (Cipher, Key) -> Key -> MeterUpdate -> Annex Bool+storeEncrypted :: HookName -> GpgOpts -> (Cipher, Key) -> Key -> MeterUpdate -> Annex Bool storeEncrypted h gpgOpts (cipher, enck) k _p = withTmp enck $ \tmp -> sendAnnex k (void $ remove h enck) $ \src -> do liftIO $ encrypt gpgOpts cipher (feedFile src) $ readBytes $ L.writeFile tmp runHook h "store" enck (Just tmp) $ return True -retrieve :: String -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex Bool+retrieve :: HookName -> Key -> AssociatedFile -> FilePath -> MeterUpdate -> Annex Bool retrieve h k _f d _p = runHook h "retrieve" k (Just d) $ return True -retrieveCheap :: String -> Key -> FilePath -> Annex Bool+retrieveCheap :: HookName -> Key -> FilePath -> Annex Bool retrieveCheap _ _ _ = return False -retrieveEncrypted :: String -> (Cipher, Key) -> Key -> FilePath -> MeterUpdate -> Annex Bool+retrieveEncrypted :: HookName -> (Cipher, Key) -> Key -> FilePath -> MeterUpdate -> Annex Bool retrieveEncrypted h (cipher, enck) _ f _p = withTmp enck $ \tmp -> runHook h "retrieve" enck (Just tmp) $ liftIO $ catchBoolIO $ do decrypt cipher (feedFile tmp) $ readBytes $ L.writeFile f return True -remove :: String -> Key -> Annex Bool+remove :: HookName -> Key -> Annex Bool remove h k = runHook h "remove" k Nothing $ return True -checkPresent :: Git.Repo -> String -> Key -> Annex (Either String Bool)+checkPresent :: Git.Repo -> HookName -> Key -> Annex (Either String Bool) checkPresent r h k = do showAction $ "checking " ++ Git.repoDescribe r- v <- lookupHook h "checkpresent"+ v <- lookupHook h action liftIO $ catchMsgIO $ check v where+ action = "checkpresent" findkey s = key2file k `elem` lines s- check Nothing = error "checkpresent hook misconfigured"+ check Nothing = error $ action ++ " hook misconfigured" check (Just hook) = do- env <- hookEnv k Nothing+ env <- hookEnv action k Nothing findkey <$> readProcessEnv "sh" ["-c", hook] env
@@ -16,6 +16,7 @@ import Common.Annex import Types.Command import Types.Key+import Types.FileMatcher import qualified Annex import qualified Git import qualified Git.Command@@ -126,7 +127,7 @@ matcher <- Limit.getMatcher map (process matcher) <$> fs where- process matcher f = ifM (matcher $ Annex.FileInfo f f)+ process matcher f = ifM (matcher $ FileInfo f f) ( a f , return Nothing ) notSymlink :: FilePath -> IO Bool
binary file changed (10440 → 10440 bytes)
@@ -56,6 +56,8 @@ import qualified Utility.InodeCache import qualified Utility.Env import qualified Utility.Gpg+import qualified Utility.Matcher+import qualified Utility.Exception #ifndef __WINDOWS__ import qualified GitAnnex #endif@@ -114,6 +116,7 @@ , check "prop_relPathDirToFile_basics" Utility.Path.prop_relPathDirToFile_basics , check "prop_relPathDirToFile_regressionTest" Utility.Path.prop_relPathDirToFile_regressionTest , check "prop_cost_sane" Config.Cost.prop_cost_sane+ , check "prop_matcher_sane" Utility.Matcher.prop_matcher_sane , check "prop_HmacSha1WithCipher_sane" Crypto.prop_HmacSha1WithCipher_sane , check "prop_TimeStamp_sane" Logs.UUIDBased.prop_TimeStamp_sane , check "prop_addLog_sane" Logs.UUIDBased.prop_addLog_sane@@ -165,6 +168,7 @@ , check "rsync remote" test_rsync_remote , check "bup remote" test_bup_remote , check "crypto" test_crypto+ , check "preferred content" test_preferred_content ] where check desc t env = do@@ -339,6 +343,40 @@ checkregularfile ingitfile checkcontent ingitfile +test_preferred_content :: TestEnv -> Test+test_preferred_content env = "git-annex preferred-content" ~: TestCase $ intmpclonerepo env $ do+ annexed_notpresent annexedfile+ -- get --auto only looks at numcopies when preferred content is not+ -- set, and with 1 copy existing, does not get the file.+ git_annex env "get" ["--auto", annexedfile] @? "get --auto of file failed with default preferred content"+ annexed_notpresent annexedfile++ git_annex env "content" [".", "standard"] @? "set expression to standard failed"+ git_annex env "group" [".", "client"] @? "set group to standard failed"+ git_annex env "get" ["--auto", annexedfile] @? "get --auto of file failed for client"+ annexed_present annexedfile+ git_annex env "ungroup" [".", "client"] @? "ungroup failed"++ git_annex env "content" [".", "standard"] @? "set expression to standard failed"+ git_annex env "group" [".", "manual"] @? "set group to manual failed"+ -- drop --auto with manual leaves the file where it is+ git_annex env "drop" ["--auto", annexedfile] @? "drop --auto of file failed with manual preferred content"+ annexed_present annexedfile+ git_annex env "drop" [annexedfile] @? "drop of file failed"+ annexed_notpresent annexedfile+ -- get --auto with manual does not get the file+ git_annex env "get" ["--auto", annexedfile] @? "get --auto of file failed with manual preferred content"+ annexed_notpresent annexedfile+ git_annex env "ungroup" [".", "client"] @? "ungroup failed"+ + git_annex env "content" [".", "exclude=*"] @? "set expression to exclude=* failed"+ git_annex env "get" [annexedfile] @? "get of file failed"+ annexed_present annexedfile+ git_annex env "drop" ["--auto", annexedfile] @? "drop --auto of file failed with exclude=*"+ annexed_notpresent annexedfile+ git_annex env "get" ["--auto", annexedfile] @? "get --auto of file failed with exclude=*"+ annexed_notpresent annexedfile+ test_lock :: TestEnv -> Test test_lock env = "git-annex unlock/lock" ~: intmpclonerepoInDirect env $ do -- regression test: unlock of not present file should skip it@@ -958,7 +996,7 @@ checkcontent :: FilePath -> Assertion checkcontent f = do- c <- readFile f+ c <- Utility.Exception.catchDefaultIO "could not read file" $ readFile f assertEqual ("checkcontent " ++ f) (content f) c checkunwritable :: FilePath -> Assertion
@@ -0,0 +1,13 @@+{- git-annex file matcher types+ -+ - Copyright 2013 Joey Hess <joey@kitenet.net>+ -+ - Licensed under the GNU GPL version 3 or higher.+ -}++module Types.FileMatcher where++data FileInfo = FileInfo+ { relFile :: FilePath -- may be relative to cwd+ , matchFile :: FilePath -- filepath to match on; may be relative to top+ }
@@ -93,6 +93,8 @@ paramFile = "FILE" paramGroup :: String paramGroup = "GROUP"+paramExpression :: String+paramExpression = "EXPR" paramSize :: String paramSize = "SIZE" paramAddress :: String
@@ -1,7 +1,7 @@ {- Interface for running a shell command as a coprocess, - sending it queries and getting back results. -- - Copyright 2012 Joey Hess <joey@kitenet.net>+ - Copyright 2012-2013 Joey Hess <joey@kitenet.net> - - Licensed under the GNU GPL version 3 or higher. -}@@ -18,29 +18,72 @@ import Common -type CoProcessHandle = (ProcessHandle, Handle, Handle, CreateProcess)+import Control.Concurrent.MVar -start :: FilePath -> [String] -> Maybe [(String, String)] -> IO CoProcessHandle-start command params env = do- (from, to, _err, pid) <- runInteractiveProcess command params Nothing env- return (pid, to, from, proc command params)+type CoProcessHandle = MVar CoProcessState +data CoProcessState = CoProcessState+ { coProcessPid :: ProcessHandle+ , coProcessTo :: Handle+ , coProcessFrom :: Handle+ , coProcessSpec :: CoProcessSpec+ }++data CoProcessSpec = CoProcessSpec+ { coProcessRestartable :: Bool+ , coProcessCmd :: FilePath+ , coProcessParams :: [String]+ , coProcessEnv :: Maybe [(String, String)]+ }++start :: Bool -> FilePath -> [String] -> Maybe [(String, String)] -> IO CoProcessHandle+start restartable cmd params env = do+ s <- start' $ CoProcessSpec restartable cmd params env+ newMVar s++start' :: CoProcessSpec -> IO CoProcessState+start' s = do+ (to, from, _err, pid) <- runInteractiveProcess (coProcessCmd s) (coProcessParams s) Nothing (coProcessEnv s)+ return $ CoProcessState pid to from s+ stop :: CoProcessHandle -> IO ()-stop (pid, from, to, p) = do- hClose to- hClose from- forceSuccessProcess p pid+stop ch = do+ s <- readMVar ch+ hClose $ coProcessTo s+ hClose $ coProcessFrom s+ let p = proc (coProcessCmd $ coProcessSpec s) (coProcessParams $ coProcessSpec s)+ forceSuccessProcess p (coProcessPid s) +{- To handle a restartable process, any IO exception thrown by the send and+ - receive actions are assumed to mean communication with the process+ - failed, and the failed action is re-run with a new process. -} query :: CoProcessHandle -> (Handle -> IO a) -> (Handle -> IO b) -> IO b-query (_, from, to, _) send receive = do- _ <- send to- hFlush to- receive from+query ch send receive = do+ s <- readMVar ch+ restartable s (send $ coProcessTo s) $ const $+ restartable s (hFlush $ coProcessTo s) $ const $+ restartable s (receive $ coProcessFrom s) $+ return+ where+ restartable s a cont+ | coProcessRestartable (coProcessSpec s) =+ maybe restart cont =<< catchMaybeIO a+ | otherwise = cont =<< a+ restart = do+ s <- takeMVar ch+ void $ catchMaybeIO $ do+ hClose $ coProcessTo s+ hClose $ coProcessFrom s+ void $ waitForProcess $ coProcessPid s+ s' <- start' (coProcessSpec s)+ putMVar ch s'+ query ch send receive rawMode :: CoProcessHandle -> IO CoProcessHandle-rawMode ch@(_, from, to, _) = do- raw from- raw to+rawMode ch = do+ s <- readMVar ch+ raw $ coProcessFrom s+ raw $ coProcessTo s return ch where raw h = do
@@ -93,7 +93,7 @@ Just fd -> do locked <- getLock fd (ReadLock, AbsoluteSeek, 0, 0) p <- readish <$> readFile pidfile- return $ check locked p+ closeFd fd `after` return (check locked p) Nothing -> return Nothing where check Nothing _ = Nothing
binary file changed (15500 → 15500 bytes)
binary file changed (3664 → 3664 bytes)
binary file changed (8648 → 8648 bytes)
binary file changed (11768 → 11768 bytes)
binary file changed (5672 → 5672 bytes)
binary file changed (21064 → 21064 bytes)
@@ -10,7 +10,7 @@ - Is forgiving about misplaced closing parens, so "foo and (bar or baz" - will be handled, as will "foo and ( bar or baz ) )" -- - Copyright 2011 Joey Hess <joey@kitenet.net>+ - Copyright 2011-2013 Joey Hess <joey@kitenet.net> - - Licensed under the GNU GPL version 3 or higher. -}@@ -26,7 +26,9 @@ match, matchM, matchMrun,- isEmpty+ isEmpty,++ prop_matcher_sane ) where import Common@@ -57,26 +59,56 @@ {- Converts a list of Tokens into a Matcher. -} generate :: [Token op] -> Matcher op-generate = go MAny+generate = simplify . process MAny . tokenGroups where- go m [] = m- go m ts = uncurry go $ consume m ts+ process m [] = m+ process m ts = uncurry process $ consume m ts -{- Consumes one or more Tokens, constructs a new Matcher,- - and returns unconsumed Tokens. -}-consume :: Matcher op -> [Token op] -> (Matcher op, [Token op])-consume m [] = (m, [])-consume m (t:ts) = go t+ consume m ((One And):rest) = term (m `MAnd`) rest+ consume m ((One Or):rest) = term (m `MOr`) rest+ consume m ((One Not):rest) = term (\p -> m `MAnd` (MNot p)) rest+ consume m ((One (Operation o)):rest) = (m `MAnd` MOp o, rest)+ consume m (Group g:rest) = (process m g, rest)+ consume m (_:rest) = consume m rest+ consume m [] = (m, [])++ term a l = + let (p, l') = consume MAny l+ in (a p, l')++ simplify (MAnd MAny x) = simplify x+ simplify (MAnd x MAny) = simplify x+ simplify (MAnd x y) = MAnd (simplify x) (simplify y)+ simplify (MOr x y) = MOr (simplify x) (simplify y)+ simplify (MNot x) = MNot (simplify x)+ simplify x = x++data TokenGroup op = One (Token op) | Group [TokenGroup op]+ deriving (Show, Eq)++tokenGroups :: [Token op] -> [TokenGroup op]+tokenGroups [] = []+tokenGroups (t:ts) = go t where- go And = cont $ m `MAnd` next- go Or = cont $ m `MOr` next- go Not = cont $ m `MAnd` MNot next- go Open = let (n, r) = consume next rest in (m `MAnd` n, r)- go Close = (m, ts)- go (Operation o) = (m `MAnd` MOp o, ts)+ go Open =+ let (gr, rest) = findClose ts+ in gr : tokenGroups rest+ go Close = tokenGroups ts -- not picky about missing Close+ go _ = One t : tokenGroups ts - (next, rest) = consume MAny ts- cont v = (v, rest)+findClose :: [Token op] -> (TokenGroup op, [Token op])+findClose l = + let (g, rest) = go [] l+ in (Group (reverse g), rest)+ where+ go c [] = (c, []) -- not picky about extra Close+ go c (t:ts) = handle t+ where+ handle Close = (c, ts)+ handle Open = + let (c', ts') = go [] ts+ in go (Group (reverse c') : c) ts'+ handle _ = go (One t:c) ts {- Checks if a Matcher matches, using a supplied function to check - the value of Operations. -}@@ -109,3 +141,29 @@ isEmpty :: Matcher a -> Bool isEmpty MAny = True isEmpty _ = False++prop_matcher_sane :: Bool+prop_matcher_sane = all (\m -> match dummy m ()) $ map generate+ [ [Operation True]+ , []+ , [Operation False, Or, Operation True, Or, Operation False]+ , [Operation True, Or, Operation True]+ , [Operation True, And, Operation True]+ , [Not, Open, Operation True, And, Operation False, Close]+ , [Not, Open, Not, Open, Not, Operation False, Close, Close]+ , [Not, Open, Not, Open, Not, Open, Not, Operation True, Close, Close]+ , [Operation True, And, Not, Operation False]+ , [Operation True, Not, Operation False]+ , [Operation True, Not, Not, Not, Operation False]+ , [Operation True, Not, Not, Not, Operation False, And, Operation True]+ , [Operation True, Not, Not, Not, Operation False, Operation True]+ , [Not, Open, Operation True, And, Operation False, Close, + And, Open, + Open, Operation True, And, Operation False, Close,+ Or,+ Open, Operation True, And, Open, Not, Operation False, Close, Close,+ Close, And,+ Open, Not, Operation False, Close]+ ]+ where+ dummy b _ = b
binary file changed (19232 → 19232 bytes)
binary file changed (7376 → 7376 bytes)
binary file changed (24540 → 24540 bytes)
binary file changed (43288 → 43288 bytes)
@@ -15,6 +15,7 @@ mkSRV, lookupSRV, lookupSRVHost,+ HostPort, ) where import Utility.Process@@ -65,9 +66,7 @@ #ifdef WITH_DNS lookupSRV (SRV srv) = do seed <- makeResolvSeed defaultResolvConf- print srv r <- withResolver seed $ flip DNS.lookupSRV $ B8.fromString srv- print r return $ maybe [] (orderHosts . map tohosts) r where tohosts (priority, weight, port, hostname) =
binary file changed (28136 → 28136 bytes)
@@ -23,8 +23,18 @@ {- Gets the contents of the TList. Blocks when empty. - TList is left empty. -} getTList :: TList a -> STM [a]-getTList tlist = D.toList <$> takeTMVar tlist+getTList tlist = D.toList <$> getTDList tlist +getTDList :: TList a -> STM (D.DList a)+getTDList = takeTMVar++{- Replaces the contents of the TList. -}+setTList :: TList a -> [a] -> STM ()+setTList tlist = setTDList tlist . D.fromList++setTDList :: TList a -> D.DList a -> STM ()+setTDList tlist = modifyTList tlist . const+ {- Takes anything currently in the TList, without blocking. - TList is left empty. -} takeTList :: TList a -> STM [a]@@ -54,6 +64,3 @@ appendTList :: TList a -> [a] -> STM () appendTList tlist l = modifyTList tlist $ \dl -> D.append dl (D.fromList l)--setTList :: TList a -> [a] -> STM ()-setTList tlist l = modifyTList tlist $ const $ D.fromList l
@@ -13,10 +13,12 @@ import Common import Control.Concurrent+#ifndef __WINDOWS__ import System.Posix.Signals #ifndef __ANDROID__ import System.Posix.Terminal #endif+#endif newtype Seconds = Seconds { fromSeconds :: Int } deriving (Eq, Ord, Show)@@ -52,15 +54,16 @@ waitForTermination :: IO () waitForTermination = do lock <- newEmptyMVar- check softwareTermination lock+#ifndef __WINDOWS__+ let check sig = void $+ installHandler sig (CatchOnce $ putMVar lock ()) Nothing+ check softwareTermination #ifndef __ANDROID__ whenM (queryTerminal stdInput) $- check keyboardSignal lock+ check keyboardSignal #endif+#endif takeMVar lock- where- check sig lock = void $- installHandler sig (CatchOnce $ putMVar lock ()) Nothing oneSecond :: Microseconds oneSecond = 1000000
binary file changed (12272 → 12272 bytes)
@@ -12,7 +12,7 @@ check, exists, download,- get+ downloadQuiet ) where import Common@@ -91,7 +91,14 @@ - for only one in. -} download :: URLString -> Headers -> [CommandParam] -> FilePath -> IO Bool-download url headers options file = +download = download' False++{- No output, even on error. -}+downloadQuiet :: URLString -> Headers -> [CommandParam] -> FilePath -> IO Bool+downloadQuiet = download' True++download' :: Bool -> URLString -> Headers -> [CommandParam] -> FilePath -> IO Bool+download' quiet url headers options file = case parseURIRelaxed url of Just u | uriScheme u == "file:" -> do@@ -103,31 +110,18 @@ _ -> return False where headerparams = map (\h -> Param $ "--header=" ++ h) headers- wget = go "wget" $ headerparams ++ [Params "-c -O"]+ wget = go "wget" $ headerparams ++ quietopt "-q" ++ [Params "-c -O"] {- Uses the -# progress display, because the normal - one is very confusing when resuming, showing - the remainder to download as the whole file, - and not indicating how much percent was - downloaded before the resume. -}- curl = go "curl" $ headerparams ++ [Params "-L -C - -# -o"]+ curl = go "curl" $ headerparams ++ quietopt "-s" ++ [Params "-L -C - -# -o"] go cmd opts = boolSystem cmd $ options++opts++[File file, File url]--{- Downloads a small file.- -- - Uses curl if available since it handles HTTPS better than- - the Haskell libraries do. -}-get :: URLString -> Headers -> IO String-get url headers = if Build.SysConfig.curl- then readProcess "curl" $- ["-s", "-L", url] ++ concatMap (\h -> ["-H", h]) headers- else case parseURI url of- Nothing -> error "url parse error"- Just u -> do- r <- request u headers GET- case rspCode r of- (2,_,_) -> return $ rspBody r- _ -> error $ rspReason r+ quietopt s+ | quiet = [Param s]+ | otherwise = [] {- Uses Network.Browser to make a http request of an url. - For example, HEAD can be used to check if the url exists,
binary file changed (6276 → 6304 bytes)
@@ -49,6 +49,7 @@ browserProc url = proc "open" [url] #else #ifdef __ANDROID__+-- Warning: The `am` command does not work very reliably on Android. browserProc url = proc "am" ["start", "-a", "android.intent.action.VIEW", "-d", url] #else
@@ -1,3 +1,31 @@+git-annex (4.20130601) unstable; urgency=medium++ * XMPP: Git push over xmpp made much more robust.+ * XMPP: Avoid redundant and unncessary pushes. Note that this breaks+ compatibility with previous versions of git-annex, which will refuse+ to accept any XMPP pushes from this version.+ * XMPP: Send pings and use them to detect when contact with the server+ is lost.+ * hook special remote: Added combined hook program support.+ * Android app: Avoid using hard links to app's lib directory, which+ is sometimes on a different filesystem than the data directory.+ * Fix bug in parsing of parens in some preferred content expressions.+ This fixes the behavior of the manual mode group.+ * assistant: Work around git-cat-file's not reloading the index after files+ are staged.+ * Improve error handling when getting uuid of http remotes to auto-ignore,+ like with ssh remotes.+ * content: New command line way to view and configure a repository's+ preferred content settings.+ * sync: Fix double merge conflict resolution handling.+ * XMPP: Fix a file descriptor leak.+ * Android: Added an "Open WebApp" item to the terminal's menu.+ * Android: Work around Android devices where the `am` command doesn't work.+ * Can now restart certain long-running git processes if they crash, and+ continue working.++ -- Joey Hess <joeyh@debian.org> Sat, 01 Jun 2013 19:16:04 -0400+ git-annex (4.20130521) unstable; urgency=low * Sanitize debian changelog version before putting it into cabal file.
@@ -51,10 +51,3 @@ `/data/data/ga.androidterm/runshell` This will launch a shell that has git-annex, git, etc in PATH.--## disk space usage--The git-annex app uses 65 MB of space on your Android device.-Do not be fooled by larger numbers that Android may display for its size,-like "273 MB". Android does not correctly calculate the size of hard linked-files, so its numbers are wrong.
@@ -0,0 +1,16 @@+[[!comment format=mdwn+ username="http://yarikoptic.myopenid.com/"+ nickname="site-myopenid"+ subject="comment 10"+ date="2013-05-24T03:11:50Z"+ content="""+>you said before the error was \"Read-only file system\". Now you're saying it's \"Cross-device link\". I'm slightly confused.++;-) Sorry for confusion, here are the details:++\"Read-only file system\" -- that error appeared when I started \"stock git annex\", i.e. from running /data/data/ga.androidterm/lib/lib.start.so .+Since you have suggested that it might be coming from hard linking command, I have ran that one manually, and that is when I got \"Cross-device link\" error, which suggests that hard linking is not the one at fault here.++I will try fresh build now+Cheers,+"""]]
@@ -0,0 +1,15 @@+[[!comment format=mdwn+ username="http://yarikoptic.myopenid.com/"+ nickname="site-myopenid"+ subject="fresh build"+ date="2013-05-24T03:21:29Z"+ content="""+With fresh build got:++u0_a39@android:/ $ git annex webapp+/system/bin/sh: git: not found++the PATH is /sbin:/system/bin:/system/xbin++where should git (and ga) reside now ? (/data somehow is not accessible now to u0_a39)+"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ nickname="joey"+ subject="comment 12"+ date="2013-05-24T03:26:33Z"+ content="""+You should be able to run /data/data/ga.androidterm/runshell even if you cannot ls /data. This adds /data/data/ga.androidterm/bin to PATH++However, the shell that the app starts is started by runshell anyway, so I don't understand how this could happen.+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkwjBDXkP9HAQKhjTgThGOxUa1B99y_WRA"+ nickname="Franck"+ subject="Still problems with my old N1/CM7"+ date="2013-05-24T06:01:18Z"+ content="""+Hi, thank you for addressing this issue! I installed the new release but now it fails in another way: the message is just \"In mgmain NJI_OnLoad\" then the terminal says that the session is closed.+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://yarikoptic.myopenid.com/"+ nickname="site-myopenid"+ subject="It starts after uninstall/install"+ date="2013-05-24T23:29:52Z"+ content="""+Hi Joey -- there is success here... previous installation was \"updated\" by installing the new package without uninstalling previous one, and that apparently didn't work correctly (I didn't even have bin/ directory you mentioned). So I have removed previous installation and reinstalled it again -- it starts now! Thanks ;)+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://yarikoptic.myopenid.com/"+ nickname="site-myopenid"+ subject="asking for ssh password in the terminal (not in web ui)"+ date="2013-05-24T23:49:40Z"+ content="""+not sure if that is a known issue: whenever \"remote server\" is added, password needs to be typed back in the original terminal... is a bit challenging to do on android and not straightforward user-wise +"""]]
@@ -0,0 +1,27 @@+[[!comment format=mdwn+ username="http://yarikoptic.myopenid.com/"+ nickname="site-myopenid"+ subject="Few other issues"+ date="2013-05-25T15:35:46Z"+ content="""+Hi again.++talking about 4.20130523-gcfe07a2 version:++- because working in the terminal to interact with git-annex probably should not be a common case on Android, may be it is worth making default type of new added repository to become a full backup? I have initiated a new one, attached a remote one, it said \"synced\" but all the files were just containing symlinks and were not usable. I had to switch to \"full backup\" (or whatever that name) to finally get directory synced++- log file might grow too large simply because of containing numerous entries for attempting connect remote repository while offline, e.g.++Please make sure you have the correct access rights+and the repository exists.+ssh: Could not resolve hostname onerussian.com: No address associated with hostname+fatal: Could not read from remote repository.++IMHO those should not be there at all, e.g. if it is known that ATM there is no network connectivity++- In addition to two existing repositories (1 local /sdcard/annex, which is also avail at/storage/sdcard0/annex + 1 remote) I have added one more local (and said to keep it in sync with original local). But it didn't work -- it \"Synced with onerussian.com_annex but not with Annex\" and claimed that the /external/extSdCard/Annex doesn't exist, although it is there (and with .git generated etc). When I restarted the deamon I got into a \"new\" Repository: /storage/extSdCard/Annex which also listed the 1st local but with \"Failed to sync with localhost\" message -- no remote one listed. Whenever I try to \"Switch repository\" to /sdcard/annex (the original local) -- it starts loading a new page but gets stuck right there. The only way to revive webui is to go back to Dashboard. Log there says (retyping from the screen so typos might be there):++error: cannot run git-receive-pack '/storage/sdcard0/annex': No such file or directory+fatal: unable to fork++"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://yarikoptic.myopenid.com/"+ nickname="site-myopenid"+ subject="comment 17"+ date="2013-05-29T02:43:29Z"+ content="""+joey -- any additional information could I provide to troubleshoot the issue? original repository seems to sync ok, but I can't \"administer\" it if I can't even switch to it...+"""]]
@@ -0,0 +1,17 @@+[[!comment format=mdwn+ username="http://aap.liquidid.net/"+ nickname="AAP"+ subject="comment 18"+ date="2013-05-30T11:23:58Z"+ content="""+I too get the 'link busybox: Read-only file system' message. Here is my phone info: ++Phone: Samsung Galaxy Y GT-S5360 (rooted) +Android: 2.3.6 Gingerbread +BusyBox path: /system/xbin/ +++Androids own terminal seems not to understand the d argument (-ld: No such file or directory) but over ssh 'ls -ld /data/data/ga.androidterm' returns+ + drwxr-x--x 1 app_97 app_97 0 May 30 12:57 /data/data/ga.androidterm/+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkwjBDXkP9HAQKhjTgThGOxUa1B99y_WRA"+ nickname="Franck"+ subject="Link issue"+ date="2013-05-22T12:01:38Z"+ content="""+Hi, I have exactly the same problem with the link that fails on my phone. However, I checked the permissions and they are as you describe on your tablet (except for the app number). At the same time, everything is fine on my tablet... The phone runs an old Cyanogenmod 7.2.0 (Android 2.3.7) while the tablet is a more recent Asus TF700T (Android 4.1.1). Let me know if you want me to run tests.+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://yarikoptic.myopenid.com/"+ nickname="site-myopenid"+ subject="why ln failed"+ date="2013-05-23T13:27:39Z"+ content="""+Finally got to check it out: so indeed hardlinking fails but not because of permissions but \"link failed Cross-device link\" that lib is -> /mnt/asec/ga.androidterm-1/lib which resides on a different partition (vfat, /dev/block/dm-2, ro) from /data (ext4, /dev/block/mmcblk0p10)+"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ nickname="joey"+ subject="comment 9"+ date="2013-05-23T18:44:46Z"+ content="""+@yarikoptic you said before the error was \"Read-only file system\". Now you're saying it's \"Cross-device link\". I'm slightly confused.++I've reworked the android app to not need any hard links. Try the current autobuild: <http://downloads.kitenet.net/git-annex/autobuild/android/git-annex.apk>+"""]]
@@ -1,3 +1,12 @@+## version 4.20130601++This is a bugfix release, featuring significant XMPP improvements and+more robustness thanks to automated fuzz testing. Recommended upgrade.++## version 4.20130521++This is a bugfix release. Recommended upgrade.+ ## version 4.20130516 This version contains numerous bug fixes, and improvements.@@ -6,10 +15,6 @@ typing needed to set up syncing to your Android phone or tablet! A few of the more advanced features may not work (or not work reliably) on Android. The Android app is still beta quality.--There is a known problem with android 4.2.2 that prevents the webapp-from opening. See [[Android_app_permission_denial_on_startup]] for a-workaround. This is also the first release with a Windows port! The Windows port is in an alpha quality state, and is missing many features.
@@ -0,0 +1,33 @@+What steps will reproduce the problem?++Building from latest source, Cabal update, cabal install --only dependencies, cabal configure, Cabal build++What is the expected output? What do you see instead?++Error message from build++...++Loading package DAV-0.2 ... linking ... done.++Loading object (static) dist/build/git-annex/git-annex-tmp/Utility/libdiskfree.o ... done++Loading object (static) dist/build/git-annex/git-annex-tmp/Utility/libmounts.o ... done++final link ... done+++Assistant/Threads/WebApp.hs:47:1: Not in scope: `getAddBoxComR'++Assistant/Threads/WebApp.hs:47:1: Not in scope: `getEnableWebDAVR'+++What version of git-annex are you using? On what operating system?++Latest version via git from git-annex.branchable.com++Debian Squeeze (6.0.6)++Please provide any additional information below.++> I noticed this earlier and fixed it. [[done]] --[[Joey]]
@@ -14,3 +14,5 @@ See this [screenshot](https://docs.google.com/file/d/0B8tqeaAn45VORU1ET1ZpTWxLTjQ/edit?usp=sharing). Feel free to ping me on IRC if you need additional info or want to test a fix.++> [[done]]; now comprehensively fixed. --[[Joey]]
@@ -0,0 +1,16 @@+### Please describe the problem.++I'm trying to use the assistant to replicate the basic dropbox functionality of having a synced folder between two machines. Instead of actually syncing file contents by default the assistant just creates broken symlinks.++### What steps will reproduce the problem?++I've setup two repositories with each other as ssh remotes and ran the assistant on each after setting them in direct mode. I can create files on each of the repositories and have them show up on the other but all that shows up is a broken link. Actual contents don't get transferred. If I do a "git annex get" I can get the contents just fine. I tried setting annex.numcopies to 2 and that didn't work either.++What I'm missing here is some setting to tell the assistant "sync the contents of every new file". What it's doing instead is unacceptable. If I have the file in both repositories and change it in one, the other repository gets it's previous version of the file replaced by a broken symlink. From my point of view for the assistant to be a dropbox replacement it should never, under any circumstances, create a broken symlink in the sync folder. I had understood that that's what direct mode was, but it's not behaving that way right now at least.++### What version of git-annex are you using? On what operating system?++My basic setup for testing is two Ubuntu 12.04 LTS machines running git-annex 4.20130501++> [[done]], broken ~/.config/git-annex/program file, which is now detected+> and worked around. --[[Joey]]
@@ -0,0 +1,36 @@+### Please describe the problem.++This is a follow up of [[Problems building on Mac OS X]].+As of 4.20130521.1, cabal still cannot resolve the dependencies.++### What steps will reproduce the problem?++ cabal update+ cabal install git-annex-4.20130521.1 --user --only-dependencies++### Please provide any additional information below.++[[!format sh """+Resolving dependencies...+cabal: Could not resolve dependencies:+trying: git-annex-4.20130521.1+trying: git-annex-4.20130521.1:+webapp+trying: yesod-form-1.3.0+trying: yesod-core-1.2.1+rejecting: yesod-default-1.2.0 (conflict: git-annex-4.20130521.1:webapp =>+yesod-default(<1.2))+rejecting: yesod-default-1.1.3.2, 1.1.3.1, 1.1.3, 1.1.2, 1.1.1, 1.1.0.2,+1.1.0.1, 1.1.0 (conflict: yesod-core==1.2.1, yesod-default => yesod-core>=1.1+&& <1.2)+rejecting: yesod-default-1.0.1.1, 1.0.1, 1.0.0 (conflict: yesod-core==1.2.1,+yesod-default => yesod-core>=1.0 && <1.1)+rejecting: yesod-default-0.6.1 (conflict: yesod-core==1.2.1, yesod-default =>+yesod-core>=0.10.1 && <0.11)+rejecting: yesod-default-0.5.0 (conflict: yesod-core==1.2.1, yesod-default =>+yesod-core>=0.9.4 && <0.10)+rejecting: yesod-default-0.4.1, 0.4.0, 0.3.1 (conflict: yesod-core==1.2.1,+yesod-default => yesod-core>=0.9 && <0.10+"""]]++> At the risk of closing early again, I have uploaded a .2 with+> hints for the version of yesod-form and yesod-static. [[done]] --[[Joey]]
@@ -0,0 +1,11 @@+### Please describe the problem.++I have a jabber account on `jabber.ccc.de`. When trying to log in to that account, I get "Unable to connect to the Jabber server. Maybe you entered the wrong password? (Error message: AuthenticationFailure)" I've typed the password enough times that I'm relatively certain that I've typed it correctly at least once. It's difficult to see behind this error message. This is the only thing that shows up in the debug log:++ [2013-05-26 21:40:16 EDT] read: host ["-t","SRV","--","_xmpp-client._tcp.jabber.ccc.de"]+ [2013-05-26 21:40:16 EDT] read: host ["-t","SRV","--","_xmpp-client._tcp.jabber.ccc.de"]++It'd be great if this error were a wee bit more verbose.++> The XMPP library has been updated to include the actual error message from the server.+> [[done]] --[[Joey]]
@@ -0,0 +1,46 @@+### Please describe the problem.++After running two repositories syncing with one another in direct mode "git status" shows unstaged changes in both.++### What steps will reproduce the problem?++1. Create two direct mode repositories with each other as ssh remotes+2. Run "git annex assistant" on each+3. Create files on each and they get synced+4. Run "git status"++In my current repository the output is:++[[!format sh """+$ git status+# On branch master+# Changes not staged for commit:+# (use "git add <file>..." to update what will be committed)+# (use "git checkout -- <file>..." to discard changes in working directory)+#+# typechange: fromgolias+# typechange: fromwintermute+#+no changes added to commit (use "git add" and/or "git commit -a")+"""]]++### What version of git-annex are you using? On what operating system?++[[!format sh """+$ git annex version+git-annex version: 4.20130516.1+build flags: Assistant Webapp Pairing Testsuite S3 WebDAV Inotify DBus XMPP+local repository version: 4+default repository version: 3+supported repository versions: 3 4+upgrade supported from repository versions: 0 1 2++$ lsb_release -a+No LSB modules are available.+Distributor ID: Ubuntu+Description: Ubuntu 12.04.2 LTS+Release: 12.04+Codename: precise+"""]]++> [[done]] --[[Joey]]
@@ -0,0 +1,32 @@+### Please describe the problem.++When a repository is set in direct mode it will still replace files with symlinks when it becomes aware of a change but still hasn't been able to sync the file contents. This can create repositories that are temporarily unusable with files replaced with broken symlinks.++### What steps will reproduce the problem?++1. Create two repositories with each other as remotes+2. Run the assistant on both+3. Create some file changes in one and watch the directory in another.+4. For a brief (or sometimes long) time the destination repository will have it's old version of the file replaced by a broken symlink++This is particularly noticeable when using XMPP as it can often be the case that the two repositories can't connect to each other directly but can talk through XMPP. This breaks using git-annex in direct mode for things like having a synced config directory across machines. Something like having "~/.bashrc" linked into "~/annex-repository/bashrc", doesn't work as there will be times when a machine is broken because .bashrc is linked to a broken symlink while it fetches a new version. ++The desired behavior would be to have git-annex in direct mode only replace older versions of files with newer versions of files.++### What version of git-annex are you using? On what operating system?++[[!format sh """+$ git annex version+git-annex version: 4.20130516.1+build flags: Assistant Webapp Pairing Testsuite S3 WebDAV Inotify DBus XMPP+local repository version: 4+default repository version: 3+supported repository versions: 3 4+upgrade supported from repository versions: 0 1 2+$ lsb_release -a+No LSB modules are available.+Distributor ID: Ubuntu+Description: Ubuntu 12.04.2 LTS+Release: 12.04+Codename: precise+"""]]
@@ -0,0 +1,31 @@+### Please describe the problem.++Other references:++https://github.com/basak/glacier-cli/pull/19+http://git-annex.branchable.com/special_remotes/glacier/#comment-a2b05b8dc2d640ee498d90398f02931c++#### Background++ * Glacier doesn't support keys that the client selects, unlike S3. If you upload to Glacier, Glacier assigns a unique ID, not the client.+ * Glacier does support an "archive description" which is immutable. It also provides this "archive description" in an inventory listing, together with the unique IDs.+ * An "archive description" is not a unique key. It's perfectly possible to upload multiple archives to Glacier with the same "archive description".+ * glacier-cli uses the "archive description" field as an upload identifier, since the unique IDs are unfriendly to users. However, since they are potentially ambiguous identifiers, it also supports disambiguation using the ID itself. See "Addressing Archives" in README.md for details.++#### The Problem++This what I believe is happening in the two reports referenced above. When git-annex is used without `--trust-glacier`, it can end up uploading the same data multiple times. From git-annex's point of view, it cannot verify that the data is already in Glacier, so it uploads again, expecting an overwrite operation if the key is already in Glacier. Since glacier-cli maps the key to an "archive description" that can be duplicated, this is not what happens. Instead, a second archive is uploaded.++When git-annex later does a "checkpresent" operation, glacier-cli fails. This is because the request is ambiguous, since there are two archives in Glacier with the same "key". The error message could be better here, but I believe that the behaviour is correct.++#### Discussion++glacier-cli can find out what data Glacier claims to have using an inventory retrieval. However, this retrieval takes about four hours and can be out of date (eg. if someone else recently deleted the archive from another client). Thus, I can understand git-annex's desire not to trust this data or a cache of it.++However, whatever we do, it is impossible to map an "upload or overwrite on key X" type command to Glacier. We'll always end up with duplicates. Even if git-annex stored the Glacier archive IDs, there is no API to replace an existing archive with the same ID, and inventories are out of date even before we retrieve them.++#### Workaround++If the problem is as I think it is, always applying `--trust-glacier` should prevent the problem from occurring in most cases, since git-annex will run "checkpresent" and glacier-cli will confirm that the archive exists.++To fix the problem after it has occurred, it should be sufficient to delete duplicates using glacier-cli, since they _should_ be identical to each other. Some enhancement of the `glacier-cli archive list` command would help here.
@@ -0,0 +1,125 @@+### Please describe the problem.++Direct mode repositories seem to initially ignore hard linked files and then when changes are done to them sync them as separate files. However, changes to one file are only propagated to that file and not to any of the others that are hardlinked to it.++### What steps will reproduce the problem?++Inside a direct mode repository linked to a ssh remote:++[[!format sh """+$ ls -l+total 0+$ echo "something" > foo+$ ln foo bar+$ ls -l+total 8+-rw-r--r-- 2 pedrocr pedrocr 10 May 29 12:08 bar+-rw-r--r-- 2 pedrocr pedrocr 10 May 29 12:08 foo+$ tail .git/annex/daemon.log+ 6c0fbd7..0bb8ef9 git-annex -> synced/git-annex+ 0bae1b4..bfedc45 master -> synced/master++sent 77 bytes received 31 bytes 72.00 bytes/sec+total size is 10 speedup is 0.09+[2013-05-29 12:08:03 WEST] Transferrer: Uploaded foo+Already up-to-date.+[2013-05-29 12:08:05 WEST] Pusher: Syncing with golias +To ssh://golias.git-annex/home/pedrocr/testsync+ 0bb8ef9..2ce5013 git-annex -> synced/git-annex+$ git status+# On branch master+# Changes not staged for commit:+# (use "git add <file>..." to update what will be committed)+# (use "git checkout -- <file>..." to discard changes in working directory)+#+# typechange: foo+#+# Untracked files:+# (use "git add <file>..." to include in what will be committed)+#+# bar+no changes added to commit (use "git add" and/or "git commit -a")+"""]]++On the remote repository:++[[!format sh """+$ ls -l+total 4+-rw-r--r-- 1 pedrocr pedrocr 10 May 29 12:08 foo+"""]]++If I now just touch the linked file on the repository:++[[!format sh """+$ touch bar+$ tail .git/annex/daemon.log++(merging synced/git-annex into git-annex...)+(Recording state in git...)+add bar (checksum...) [2013-05-29 12:12:49 WEST] Committer: Committing changes to git+[2013-05-29 12:12:49 WEST] Pusher: Syncing with golias +Already up-to-date.+To ssh://golias.git-annex/home/pedrocr/testsync+ 2ce5013..d36166b git-annex -> synced/git-annex+ bfedc45..ee3a7a1 master -> synced/master+Already up-to-date.+"""]]++On the remote repository:++[[!format sh """+$ ls -l+total 8+-rw-r--r-- 1 pedrocr pedrocr 10 May 29 12:08 bar+-rw-r--r-- 1 pedrocr pedrocr 10 May 29 12:08 foo+"""]]++Note that now bar has been synced as a new file and not a hardlink as it should be (the 1's after the permissions). ++The sync also isn't acting properly on the linked files. For example. ++First in the origin repository:++[[!format sh """+$ cat bar+something+$ cat foo+something+$ echo "someotherthing" > bar+$ cat bar+someotherthing+$ cat foo+someotherthing+"""]]++The result in the destination:++[[!format sh """+$ cat bar+someotherthing+$ cat foo+something+"""]]++So even if the intended behavior is for hardlinked files to be synced as two separate files the sync isn't correct because the two files changed in the origin and only one of them changed in the destination. This probably needs to be fixed with actual hard links for real filesystems and with some copying for crippled filesystems.++### What version of git-annex are you using? On what operating system?++[[!format sh """+$ git annex version+git-annex version: 4.20130516.1+build flags: Assistant Webapp Pairing Testsuite S3 WebDAV Inotify DBus XMPP+local repository version: 4+default repository version: 3+supported repository versions: 3 4+upgrade supported from repository versions: 0 1 2+$ lsb_release -a+No LSB modules are available.+Distributor ID: Ubuntu+Description: Ubuntu 12.04.2 LTS+Release: 12.04+Codename: precise+"""]]++
@@ -0,0 +1,61 @@+### Please describe the problem.++I added a lot of files to my annex in direct mode. Now I want to switch to indirect mode. git-annex status and indirect create an out-of-memory error.++### What steps will reproduce the problem?++I am not really sure, I added a lot of files to the annex, almost 3TB.+Then either git-annex status or git-annex indirect cause a similar error (see below).+++### What version of git-annex are you using? On what operating system?++git-annex version: 4.20130501-g4a5bfb3+local repository version: 4+default repository version: 3+supported repository versions: 3 4+upgrade supported from repository versions: 0 1 2+build flags: Assistant Webapp Pairing Testsuite S3 WebDAV Inotify DBus XMPP++Ubuntu precise+3.2.0-26-generic+++### Please provide any additional information below.++[[!format sh """+# If you can, paste a complete transcript of the problem occurring here.+# If the problem is with the git-annex assistant, paste in .git/annex/debug.log+git-annex status+supported backends: SHA256E SHA1E SHA512E SHA224E SHA384E SHA256 SHA1 SHA512 SHA224 SHA384 WORM URL+supported remote types: git S3 bup directory rsync web webdav glacier hook+repository mode: direct+trusted repositories: 0+semitrusted repositories: 7+ 00000000-0000-0000-0000-000000000001 -- web+ 0b8e6666-80d5-11e2-adf3-6f4d3d6ef0aa -- marek@x4:~/tmp/annex+ 65c057c6-6027-11e2-84b0-b77d71696e49 -- here (.)+ 96b31c5e-6524-11e2-b136-fbd1a03b2799 -- BackupOnGlacier+ b509c388-629a-11e2-be5f-d376e201ad86 -- marek@x201:~/AllData+ c636e33c-6e31-11e2-a9c4-a3c5546d69d9 -- desktop+ fbaa1c3a-60d7-11e2-842f-9348368d2f4c -- .+untrusted repositories: 0+dead repositories: 0+transfers in progress: none+available local disk space: 81 gigabytes (+1 megabyte reserved)+temporary directory size: 9 megabytes (clean up with git-annex unused)+local annex keys: 61396+local annex size: 3 terabytes+known annex keys: git-annex: out of memory (requested 985661440 bytes)++OR++git-annex indirect+commit git-annex: out of memory (requested 985661440 bytes)++++++# End of transcript or log.+"""]]
@@ -0,0 +1,19 @@+What steps will reproduce the problem?++Adding files to a local annex set up to sync to a remote S3 one+++What is the expected output? What do you see instead?++It syncs, but maxes out the uplink+++What version of git-annex are you using? On what operating system?++3.20121112 on Debian testing+++Please provide any additional information below.++The man page lists how to configure rate limiting for rsync, not sure how to do it for this+
@@ -0,0 +1,38 @@+### Please describe the problem.++If the assistant daemon is killed, ssh mux sessions are left behind. Incidentally there may be a better way to stop the assistant daemon besides "killall git-annex" but I haven't found it in the docs.++### What steps will reproduce the problem?++[[!format sh """+$ ps aux | grep mux+$ git-annex assistant+$ date > fromwintermute # Just causing a change that needs to be pushed, any will do+$ ps aux | grep mux+pedrocr 32665 0.0 0.0 6396 948 ? Ss 11:06 0:00 ssh: /home/pedrocr/testsync/.git/annex/ssh/golias.git-annex [mux]+$ killall git-annex+$ ps aux | grep mux+pedrocr 32665 0.0 0.0 6396 948 ? Ss 11:06 0:00 ssh: /home/pedrocr/testsync/.git/annex/ssh/golias.git-annex [mux]+"""]]++### What version of git-annex are you using? On what operating system?++[[!format sh """+$ git annex version+git-annex version: 4.20130516.1+build flags: Assistant Webapp Pairing Testsuite S3 WebDAV Inotify DBus XMPP+local repository version: 4+default repository version: 3+supported repository versions: 3 4+upgrade supported from repository versions: 0 1 2+$ lsb_release -a+No LSB modules are available.+Distributor ID: Ubuntu+Description: Ubuntu 12.04.2 LTS+Release: 12.04+Codename: precise+"""]]++++> [[done]] --[[Joey]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="http://joey.kitenet.net/"+ nickname="joey"+ subject="comment 1"+ date="2012-01-06T03:04:35Z"+ content="""+Despite `status` listing S3 support, your git-annex is actually built with S3stub, probably because it failed to find the necessary S3 module at build time. Rebuild git-annex and watch closely, you'll see \"** building without S3 support\". Look above that for the error and fix it.++It was certianly a bug that it showed S3 as supported when built without it. I've fixed that.+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://joey.kitenet.net/"+ nickname="joey"+ subject="comment 2"+ date="2012-01-06T03:08:28Z"+ content="""+BTW, you'll want to \"make clean\", since the S3stub hack symlinks a file into place and it will continue building with S3stub even if you fix the problem until you clean.+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkey8WuXUh_x5JC2c9_it1CYRnVTgdGu1M"+ nickname="Dustin"+ subject="Thank you!"+ date="2012-01-06T03:38:27Z"+ content="""+make clean and rebuild worked... Thank you+"""]]
@@ -0,0 +1,89 @@+### Please describe the problem.++The `manual` content mode doesn't follow the description provided in the help page, instead it seems to collect content.++### What steps will reproduce the problem?++1. Create a new git annex repository using the webapp, set the content type to `client`.+2. Create another repository, and set the content type to `manual`.+3. Copy something into the `client` repository.+4. It will be pushed/pulled into the `manual` repository.++### What version of git-annex are you using? On what operating system?++ git-annex version: 4.20130521-g25dba9d+ Ubuntu 13.04 x64.++### Please provide any additional information below.++I have also noticed very weird behaviour that I have been unable to replicate in testing, but I will describe the setup that it currently happens in:+I have 3x repositories, one a `client` repository, and the other two are set to `manual`. When put a new file into the `client` repository, it is pushed onto the two `manual` repositories. When these repositories have received it, the client drops the file and re-downloads it from one of the `manual` repositories. Once it's been pushed, deleted, and pulled, everything is happy... but the extra step makes no difference.++[[!format sh """+[2013-05-22 20:41:44 EST] main: starting assistant version 4.20130521-g25dba9d+[2013-05-22 20:41:44 EST] TransferScanner: Syncing with test3, test2 +Already up-to-date.++(scanning...) [2013-05-22 20:41:44 EST] Watcher: Performing startup scan+Already up-to-date.+Already up-to-date.+++(started...) From /home/valorin/workspace/tmp/test3+ f285dc2..406c20c git-annex -> test3/git-annex+ cdf2ad3..508983c master -> test3/master+From /home/valorin/workspace/tmp/test2+ 1e04829..1c03533 git-annex -> test2/git-annex+ 8ad4bd3..18a5408 master -> test2/master+Updating 508983c..18a5408+Fast-forward+Already up-to-date.+To /home/valorin/workspace/tmp/test2+ 4e49293..a66ce5d git-annex -> synced/git-annex+ 508983c..18a5408 master -> synced/master+To /home/valorin/workspace/tmp/test3+ 4e49293..a66ce5d git-annex -> synced/git-annex+ 508983c..18a5408 master -> synced/master+Already up-to-date.+Already up-to-date.+[2013-05-22 20:42:07 EST] Committer: Adding Firefly S..acked.m4v++(merging test3/git-annex into git-annex...)+(merging test2/git-annex into git-annex...)+(Recording state in git...)+++++add Firefly S01E03 Bushwhacked.m4v (checksum...) [2013-05-22 20:42:15 EST] Committer: Committing changes to git+[2013-05-22 20:42:15 EST] Pusher: Syncing with test3, test2 +Already up-to-date.+To /home/valorin/workspace/tmp/test2+ a66ce5d..a6773dd git-annex -> synced/git-annex+ 18a5408..f9e7692 master -> synced/master+To /home/valorin/workspace/tmp/test3+ a66ce5d..a6773dd git-annex -> synced/git-annex+ 18a5408..f9e7692 master -> synced/master+Already up-to-date.+Already up-to-date.+[2013-05-22 20:42:26 EST] Transferrer: Uploaded Firefly S..acked.m4v+[2013-05-22 20:42:26 EST] Pusher: Syncing with test3, test2 +To /home/valorin/workspace/tmp/test3+ a6773dd..c35f992 git-annex -> synced/git-annex+To /home/valorin/workspace/tmp/test2+ a6773dd..c35f992 git-annex -> synced/git-annex+[2013-05-22 20:42:35 EST] Transferrer: Uploaded Firefly S..acked.m4v+[2013-05-22 20:42:35 EST] Pusher: Syncing with test3, test2 +To /home/valorin/workspace/tmp/test3+ c35f992..9e47813 git-annex -> synced/git-annex+To /home/valorin/workspace/tmp/test2+ c35f992..9e47813 git-annex -> synced/git-annex+[2013-05-22 20:42:44 EST] Pusher: Syncing with test3, test2 +Everything up-to-date+Everything up-to-date+"""]]++> It turns out there was a bug in the preferred content expression parser,+> that made it parse the expression for manual mode (but I think no other standard+> expression) quite wrong, as if it had parens in the wrong place. This explains+> the broken behavior. [[fixed|done]] --[[Joey]]
@@ -0,0 +1,37 @@+### Please describe the problem.++I have an annex which contains all my photos. There are repositories on my laptop and my home server as well as an s3 backup (for which syncing is currently disabled). I switched the copy on my laptop to manual mode via 'git annex vicfg' (this correctly shows up in the webapp). I then proceeded to drop several folders (each containing a year's worth of photos). This works fine, however the assistant immediately starts downloading the dropped files from the server! Numcopies is set to 1 and the problem exists with the server in both the 'transfer' and 'backup' groups (haven't tried others).++### What steps will reproduce the problem?++1. Create a repo with some files.+2. Create a bare-git remote on another machine.+3. Make sure the assistant is running for the repo in question. +4. Switch your local copy to manual mode.+5. Drop some files.+6. Watch as the assistant re-downloads them!++### What version of git-annex are you using? On what operating system?++git-annex version: 4.20130501+local repository version: unknown+default repository version: 3+supported repository versions: 3 4+upgrade supported from repository versions: 0 1 2+build flags: Assistant Webapp Pairing Testsuite S3 WebDAV Inotify DBus XMPP++Debian Testing/Sid.++### Please provide any additional information below.++If it's relevant I switched the local repository to indirect mode by manually shutting down the assistant and running 'git annex indirect' before restarting the assistant. This was done before any of the steps above.++[[!format sh """+# If you can, paste a complete transcript of the problem occurring here.+# If the problem is with the git-annex assistant, paste in .git/annex/daemon.log+++# End of transcript or log.+"""]]++> [[done]] --[[Joey]]
@@ -0,0 +1,15 @@+Running the 'assistant' branch, I occassionally get++To myhost1:/Users/jtang/annex+ ! [rejected] master -> synced/master (non-fast-forward)+error: failed to push some refs to 'myhost1:/Users/jtang/annex'+hint: Updates were rejected because a pushed branch tip is behind its remote+hint: counterpart. Check out this branch and merge the remote changes+hint: (e.g. 'git pull') before pushing again.+hint: See the 'Note about fast-forwards' in 'git push --help' for details.+(Recording state in git...)++manually running a 'git annex sync' usually fixes it, I guess once the sync command runs periodically this problem will go away, is this even OSX specific? I don't quite get the behaviour that is described in [[design/assistant/blog/day_15__its_aliiive]].++> With my changes today, I've seen it successfully recover from this+> situation. [[done]] --[[Joey]]
@@ -0,0 +1,11 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ ip="4.154.3.194"+ subject="comment 10"+ date="2013-01-19T16:13:20Z"+ content="""+The app uses the version of git included in it, because using the system's installed version if there is one is likely to run into other version incompatabilities. ++You can either install git-annex using cabal and homebrew, as documented, or you could go in and delete+all the git programs out of the app, and then it'd use the system's git stuff instead.+"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ nickname="joey"+ subject="comment 10"+ date="2013-04-16T17:14:13Z"+ content="""+@Jeremy, it's been a long time since anyone reported having the \"LSOpenURLsWithRole()\". It seemed to go away when the dmg was fixed to include all the necessary libraries. So my guess is you installed it wrong, somehow, and perhaps it's not finding those libraries that are part of the dmg.++You should be able to start the assistant by running it directly from the dmg.+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawlkAghrKEvslMcV2INKUhtPPMsfnzQyyd8"+ nickname="Jeremy"+ subject="comment 11"+ date="2013-04-17T02:02:00Z"+ content="""+@joey, figured it out. There was a program added to the startup list, presumably from when I ran things from the dmg a while ago. Once I delete that, it started fine. Of course, I forgot to write down the name of the program... I remember it had an LW in the name.+"""]]
@@ -0,0 +1,26 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawlYy4BrJyV1PdfqzevCVziXRp89iUH6Xzw"+ nickname="Christopher"+ subject="Code signing errors in log on starting git-annex.app"+ date="2013-01-19T22:30:32Z"+ content="""+When I run via the App and set up a fresh repo, i get some Console.app spam (looks like one per file added to the repo dir... or maybe one per git command?):++ 2013-01-19 2:44:55.000 PM kernel[0]: CODE SIGNING: cs_invalid_page(0x1008b4000): p=73995[git] clearing CS_VALID+ 2013-01-19 2:44:55.000 PM kernel[0]: CODE SIGNING: cs_invalid_page(0x10f99e000): p=73996[git] clearing CS_VALID+ 2013-01-19 2:44:55.000 PM kernel[0]: CODE SIGNING: cs_invalid_page(0x102b44000): p=73997[git] clearing CS_VALID+ 2013-01-19 2:44:55.000 PM kernel[0]: CODE SIGNING: cs_invalid_page(0x1029f4000): p=73998[git] clearing CS_VALID+ ...++and nothing seems to work. The page address and the pid increment steadily with each line. I'm using 10.8.2 (12C60) on a Mac Pro, and grabbed:++ /git-annex/OSX/current/10.8.2_Mountain_Lion/git-annex.dmg.bz2 ++(published 14-Jan-2013 15:19)++It seems to be a code signing issue, perhaps with the vendored git binaries. While things are sort-of working, the web app shows the files flying by really fast. ++Using a fresh repo via `git annex webapp` works great (I built that after much teeth-knashing, brew install/link cycles, and then cabal install git-annex). ++I am very excited for this to work, this is exactly what I've been waiting for to replace dropbox. Came very close to writing it myself a few times (and in Haskell no less!!). +"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkCw26IdxXXPBoLcZsQFslM67OJSJynb1w"+ nickname="Alexander"+ subject="standalone app dmg won't open in OSX 10.8.3"+ date="2013-04-29T18:05:54Z"+ content="""+I downloaded the app build from [http://downloads.kitenet.net/git-annex/OSX/current/10.8.2_Mountain_Lion/](http://downloads.kitenet.net/git-annex/OSX/current/10.8.2_Mountain_Lion/) and unpacked it, but the .dmg won't open. I can run other dmg's successfully. ++Trying to install git-annex via cabal on the same machine led to this issue: [http://git-annex.branchable.com/tips/Building_git-annex_on_Debian_OR___37____164____35____34____164____37____38____34____35___Haskell__33__/#comment-7cc94df1bf9a75a6d03369f3897d6816](http://git-annex.branchable.com/tips/Building_git-annex_on_Debian_OR___37____164____35____34____164____37____38____34____35___Haskell__33__/#comment-7cc94df1bf9a75a6d03369f3897d6816)+"""]]
@@ -0,0 +1,11 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawmYiJgOvC4IDYkr2KIjMlfVD9r_1Sij_jY"+ nickname="Douglas"+ subject="Error creating remote repository using ssh on OSX"+ date="2013-01-25T13:18:40Z"+ content="""+There is an issue with creating remote repositories using ssh (the problem may require using a different account name.) I filed the following bug:+++<http://git-annex.branchable.com/bugs/Error_creating_remote_repository_using_ssh_on_OSX/>+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkN91jAhoesnVI9TtWANaBPaYjd1V9Pag8"+ nickname="Benjamin"+ subject="Package for older OS X"+ date="2012-11-17T12:36:45Z"+ content="""+Is there an option to provide application bundle for older versions of OS X? The last time I tried the bundle wouldn't work under 10.5. If no specific features from newer OS X versions are required, it could be enough to add a simple switch when building.+"""]]
@@ -0,0 +1,15 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkurjhi0CRJvgm7QNaZDWS9hitBtavqIpc"+ nickname="Bret"+ subject="git-annex.app Not working on 32 bit machines"+ date="2012-11-03T19:18:47Z"+ content="""+I tried running the git-annex.app on my Core Duo Macbook pro, and it does not run at all. I get an error on my system.log++`Nov 3 12:13:26 Bret-Mac [0x0-0x15015].com.branchable.git-annex[155]: /Applications/git-annex.app/Contents/MacOS/runshell: line 52: /Applications/git-annex.app/Contents/MacOS/bin/git-annex: Bad CPU type in executable+Nov 3 12:13:26 Bret-Mac com.apple.launchd.peruser.501[92] ([0x0-0x15015].com.branchable.git-annex[155]): Exited with exit code: 1`++It works on my 64 bit machine, and this has become quite the problem for a while now, where people with newer macs dont compile back for a 32bit machine. ++Is there any hope for a pre-compiled binary that works on a 32 bit machine?+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkSq2FDpK2n66QRUxtqqdbyDuwgbQmUWus"+ nickname="Jimmy"+ subject="comment 8"+ date="2012-11-07T16:08:00Z"+ content="""+I've been updating my haskell platform install recently, i used to try and get the builder to spit out 32/64bit binaries, but recently it's just become too messy, I've just migrated to a full 64bit build system. I'm afraid I won't be able to provide 32bit builds any more.+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawmOsimKUgz6rxpmsS_nrBQGavEYyUpDlsE"+ nickname="Tim"+ subject="OS X 10.8.2"+ date="2013-01-11T00:07:54Z"+ content="""+Double click on the app, give permission for it to run and ... nothing+"""]]
@@ -0,0 +1,17 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawmRFKwny4rArBaz-36xTcsJYqKIgdDaw5Q"+ nickname="Andrew"+ subject="Prefer the system/path git binaries if they're a newer version"+ date="2013-01-19T06:20:38Z"+ content="""+I have used homebrew to install git v1.8.0.2 but git-annex.app packages git v1.7.10.2. git 1.7 crashes due to some newer directives in my global git config.++ error: Malformed value for push.default: simple+ error: Must be one of nothing, matching, tracking or current.+ fatal: bad config file line 38 in /Users/akraut/.gitconfig+ + git-annex: fd:13: hGetLine: end of file+ failed+ git-annex: webapp: 1 failed++"""]]
@@ -0,0 +1,18 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawlkAghrKEvslMcV2INKUhtPPMsfnzQyyd8"+ nickname="Jeremy"+ subject="Unable to start assistant"+ date="2013-04-16T01:07:05Z"+ content="""+I got the git-annex assistant to work once a long time ago when I ran it the first time directly from the dmg. Ever since then (i.e., after putting it in my applications folder) I have never gotten it to run. Wondering if anyone else has experienced this?++I am running OSX 10.7.5 and just pulled the latest app (05-Apr-2013 10:17).++For reference, when I try to kick off the the assistant from the command line I get the error:++ $ open /Applications/git-annex.app+ LSOpenURLsWithRole() failed with error -10810 for the file /Applications/git-annex.app.++I am wondering if there is some sort of file or modification that was made when I accidently kicked it off initially from the dmg, if so any thoughts on what to clear / change?++"""]]
@@ -0,0 +1,62 @@+### Please describe the problem.++Installing via Cabal fails due to dependency conflicts with yesod. If I build without the webapp flag, the problem disappears.++### What steps will reproduce the problem?+Running `cabal install c2hs git-annex --bindir=$HOME/bin`.++### What version of git-annex are you using? On what operating system?+I was attempting to install 4.20130521 from Hackage. My operating system is Mac OS X 10.6.8. Cabal-install is at 0.14.0.++### Please provide any additional information below.++[[!format sh """+# If you can, paste a complete transcript of the problem occurring here.+# If the problem is with the git-annex assistant, paste in .git/annex/debug.log+Resolving dependencies...+cabal: Could not resolve dependencies:+trying: git-annex-4.20130521 (user goal)+trying: git-annex-4.20130521:+webapp+trying: yesod-default-1.2.0 (dependency of git-annex-4.20130521:+webapp)+trying: yesod-core-1.2.1 (dependency of yesod-default-1.2.0)+trying: cookie-0.4.0.1/installed-9d9... (dependency of yesod-core-1.2.1)+next goal: yesod (dependency of git-annex-4.20130521:+webapp)+rejecting: yesod-1.2.0.1, 1.2.0 (conflict: git-annex-4.20130521:webapp =>+yesod(<1.2))+rejecting: yesod-1.1.9.3, 1.1.9.2, 1.1.9.1, 1.1.9, 1.1.8.2, 1.1.8.1, 1.1.8,+1.1.7.2, 1.1.7.1, 1.1.7, 1.1.6, 1.1.5, 1.1.4.1, 1.1.4 (conflict:+yesod-core==1.2.1, yesod => yesod-core>=1.1.5 && <1.2)+rejecting: yesod-1.1.3.1, 1.1.3, 1.1.2, 1.1.1.2, 1.1.1, 1.1.0.3, 1.1.0.2,+1.1.0.1, 1.1.0 (conflict: yesod-core==1.2.1, yesod => yesod-core>=1.1 && <1.2)+rejecting: yesod-1.0.1.6, 1.0.1.5, 1.0.1.4, 1.0.1.3, 1.0.1.2, 1.0.1.1, 1.0.1,+1.0.0.2, 1.0.0.1, 1.0.0 (conflict: yesod-core==1.2.1, yesod => yesod-core>=1.0+&& <1.1)+rejecting: yesod-0.10.2, 0.10.1.4, 0.10.1.3, 0.10.1.2, 0.10.1.1, 0.10.1+(conflict: yesod-core==1.2.1, yesod => yesod-core>=0.10.1 && <0.11)+rejecting: yesod-0.9.4.1, 0.9.4, 0.9.3.4, 0.9.3.3, 0.9.3.2 (conflict:+yesod-core==1.2.1, yesod => yesod-core>=0.9.3.4 && <0.10)+rejecting: yesod-0.9.3.1, 0.9.3, 0.9.2.2, 0.9.2.1, 0.9.2, 0.9.1.1 (conflict:+yesod-core==1.2.1, yesod => yesod-core>=0.9.1.1 && <0.10)+rejecting: yesod-0.9.1 (conflict: yesod-core==1.2.1, yesod => yesod-core>=0.9+&& <0.10)+rejecting: yesod-0.8.2.1, 0.8.2, 0.8.1 (conflict: yesod-core==1.2.1, yesod =>+yesod-core>=0.8.1 && <0.9)+rejecting: yesod-0.8.0 (conflict: yesod-core==1.2.1, yesod => yesod-core>=0.8+&& <0.9)+rejecting: yesod-0.7.3, 0.7.2 (conflict: yesod-core==1.2.1, yesod =>+yesod-core>=0.7.0.2 && <0.8)+rejecting: yesod-0.7.1 (conflict: yesod-core==1.2.1, yesod =>+yesod-core>=0.7.0.1 && <0.8)+rejecting: yesod-0.7.0 (conflict: yesod-core==1.2.1, yesod => yesod-core>=0.7+&& <0.8)+rejecting: yesod-0.6.7, 0.6.6, 0.6.5, 0.6.4, 0.6.3, 0.6.2, 0.6.1.2, 0.6.1.1,+0.6.1, 0.6.0.2, 0.6.0.1, 0.6.0, 0.5.4.2, 0.5.4.1, 0.5.4, 0.5.3, 0.5.2, 0.5.1,+0.5.0.3, 0.5.0.2, 0.5.0.1, 0.5.0, 0.4.1, 0.4.0.3, 0.4.0.2, 0.4.0.1, 0.4.0+(conflict: cookie => time==1.4/installed-d61..., yesod => time>=1.1.4 && <1.3)+rejecting: yesod-0.3.1.1, 0.3.1, 0.3.0, 0.2.0, 0.0.0.2, 0.0.0.1, 0.0.0+(conflict: cookie => time==1.4/installed-d61..., yesod => time>=1.1.3 && <1.2)+# End of transcript or log.+"""]]++> Not OSX specific. I have added a version hint that makes cabal work and uploaded+> a point release with this fix. [[done]] --[[Joey]]
@@ -0,0 +1,30 @@+What steps will reproduce the problem?++Add an encrypted rsync remote by it's 'Host' value in ~/.ssh/config.++eg.:++cat ~/.ssh/config | grep Host++ Host serverNick++git annex initremote rsyncRemote type=rsync rsyncurl=serverNick:/home/USER/Music encryption=USER@gmail.com++git annex copy some\ artist --to serverNick+++What is the expected output? What do you see instead?++I'd expect it to remember the key password like a normal ssh remote. Instead I get asked for the key password 3 times for each file in the folder.++What version of git-annex are you using? On what operating system?++3.20130216. Arch x64 (up to date as of 2013-03-07)++Please provide any additional information below.+++[[!meta title="rsync special remote does not use ssh connection caching"]]++> [[done]]; ssh connection caching is now done for these remotes.+> --[[Joey]]
@@ -0,0 +1,30 @@+#What steps will reproduce the problem?++1. Create a new repository in indirect mode.++2. Add the same file twice under a different name. Now you have two symlinks pointing to the same file under .git/annex/objects/++3. Switch to direct mode. The first symlink gets replaced by the actual file. The second stays unchanged, pointing to nowhere. But git annex whereis still reports it has a copy.++4. Delete the first file. Git annex whereis still thinks it has a copy of file 2, which is not true -> data loss.++#What is the expected output? What do you see instead?++When switching to direct mode, both symlinks should be replaced by a copy (or at least a hardlink) of the actual file.++> The typo that caused this bug is fixed. --[[Joey]] ++#What version of git-annex are you using? On what operating system?++3.20130107 on Arch Linux x64++#Please provide any additional information below.++The deduplication performed by git-annex is very dangerous in itself+because files with identical content become replaced by references to the+same file without the user necessarily being aware. Think of the user+making a copy of a file, than modifying it. He would expect to end up with+two files, the unchanged original and the modified copy. But what he really+gets is two symlinks pointing to the same modified file.++> I agree, it now copies rather than hard linking. [[done]] --[[Joey]]
@@ -0,0 +1,14 @@+### Please describe the problem.++When running a command like `git annex copy --not --in bucket --to bucket`, I got:++`fatal: bad config file line 1 in /home/jim/tmp/git-annex14898.tmp`++I caught `git-annex14898.tmp` before it was deleted and it contained an HTML error page.+I have a remote `https://git.example.com/jim/annex.git`, and it appears that git-annex+is requesting `https://git.example.com/jim/annex.git/config`. My server returns a 401 +Forbidden and an error page for that URL, but git-annex tries to use the response as a config file anyway.++Jim++> [[fixed|done]] --[[Joey]]
@@ -18,3 +18,5 @@ # End of transcript or log. """]]++> [[done]]; the OSX gpg was broken for a while, now fixed. --[[Joey]]
@@ -0,0 +1,30 @@+### Please describe the problem.++The assistant seems to only sync files and not directories, so empty directories will not be synced.++### What steps will reproduce the problem?++- Create an empty directory on HostA+- See that nothing gets synced (daemon.log is silent) and the directory doesn't exist on the other HostB+- Create an empty file inside the empty directory on HostA+- See that now HostB has the empty file inside the directory++I'm sure this comes directly from the git behavior but is at least surprising for a direct mode repository using the assistant.++### What version of git-annex are you using? On what operating system?++[[!format sh """+$ git annex version+git-annex version: 4.20130516.1+build flags: Assistant Webapp Pairing Testsuite S3 WebDAV Inotify DBus XMPP+local repository version: 4+default repository version: 3+supported repository versions: 3 4+upgrade supported from repository versions: 0 1 2+$ lsb_release -a+No LSB modules are available.+Distributor ID: Ubuntu+Description: Ubuntu 12.04.2 LTS+Release: 12.04+Codename: precise+"""]]
@@ -0,0 +1,45 @@+### Please describe the problem.++The assistant does not sync file permissions so if you set something as executable it won't be set the same on the other repositories.++### What steps will reproduce the problem?++On the first host:++[[!format sh """+$ echo -e '#!/bin/sh\necho "Hello World!"' > testscript+$ chmod ugo+x testscript +$ ./testscript +Hello World!+$ ls -l+total 4+-rwxr-xr-x 1 pedrocr pedrocr 30 May 31 20:00 testscript+"""]]++And on the second host:++[[!format sh """+$ ls -l+total 4+-rw-r--r-- 1 pedrocr pedrocr 30 May 31 20:00 testscript+$ ./testscript+bash: ./testscript: Permission denied+"""]]++### What version of git-annex are you using? On what operating system?++[[!format sh """+$ git annex version+git-annex version: 4.20130516.1+build flags: Assistant Webapp Pairing Testsuite S3 WebDAV Inotify DBus XMPP+local repository version: 4+default repository version: 3+supported repository versions: 3 4+upgrade supported from repository versions: 0 1 2+$ lsb_release -a+No LSB modules are available.+Distributor ID: Ubuntu+Description: Ubuntu 12.04.2 LTS+Release: 12.04+Codename: precise+"""]]
@@ -0,0 +1,27 @@+### Please describe the problem.++This is a one-off thing, not a reproducible bug. It was just so weird that I wanted to make a note of it in case somebody else had the same problem and it was reproducible.++I have a remote on the a USB drive which I mount once in a while on /Volumes/TOSHIBAEXT which has a remote on /Volumes/TOSHIBAEXT/annex. It's a remote which I created by hand using "git clone" a long time ago, not something the assistant set up for me.++Anyway, today the assistant kept reporting that it could not sync to it. I didn't know why, because I checked in my Finder sidebar and it showed a mounted drive called TOSHIBAEXT. It's only when I checked with the command line that I noticed something was up! There was now an ordinary directory at /Volumes/TOSHIBAEXT/annex. This had apparently been created at some point when the drive was unmounted, so when it re-mounted, because there was a directory in the way, it re-mounted at "/Volumes/TOSHIBAEXT 1". But it was displayed in the finder sidebar as just "TOSHIBAEXT" anyway because the finder hides this workaround from the user for whatever reason.++Presumably git-annex assistant at some point, for some reason, created an ordinary directory where it expected to find the annex.++I wonder if this may have to do with the fact that this is a non-bare, created-by-hand repo, from before I was using the assistant, not a normal bare remote that the assistant would have created for me if I'd been using the webapp.++### What steps will reproduce the problem?++I've only seen it once, and report the bug not as an outstanding issue but only as a heads-up that this has ever happened.++### What version of git-annex are you using? On what operating system?++git-annex version: 4.20130501-gb61740e++OS X lion (10.7)++### Please provide any additional information below.++I wasn't logging when this happened.++Again, just a heads-up; I'll keep my eye open for this happening again and post more info if it does.
@@ -0,0 +1,34 @@+After a series of pretty convoluted copying files around between annex'd repos and pulling changes around between repos. I noticed that occassionally when git-annex tries to stage files (the `.git-annex/*/*/*logs`) git some times gets wedged and doing a "git commit -a" doesn't seem to work or files might not get added thus leaving a bunch of untracked files or modified files that aren't staged for a commit.++I tried running a *`git rm --cached -f -r *`* then *git add -u .git-annex/* or the usual *git add* then a commit fixes things for me. If I don't do that then my subsequent merges/pulls will fail and result in *no known copies of files* I suspect git-annex might have just touched some file modes and git picked up the changes but got confused since there was no content change. It might also just be a git on OSX thing and it doesn't affect linux/bsd users.++For now it's just a bit of extra work for me when it does occur but it does not seem to occur often.++> What do you mean when you say that git "got wedged"? It hung somehow?+>+> If git-annex runs concurrently with another git command that locks+> the repository, its git add of log files can fail.+> +> Update: Also, of course, if you are running a "got annex get" or+> similar, and ctrl-c it after it has gotten some files, it can+> end up with unstaged or in some cases un-added log files that git-annex+> wrote -- since git-annex only stages log files in git on shutdown, and+> ctrl-c bypasses that.+> --[[Joey]] ++>> It "got wedged" as in git doesn't let me commit anything, even though it tells me that there is stuff to be committed in the staging area.++>>> I've never seen git refuse to commit staged files. There would have to+>>> be some error message? --[[Joey]] ++>>>> there were no error messages at all++>>>>> Can I see a transcript? I'm having difficulty getting my head around+>>>>> what git is doing. Sounds like the files could just not be `git+>>>>> added` yet, but I get the impression from other things that you say+>>>>> that it's not so simple. --[[Joey]] ++This turns out to be a bug in git, and I have posted a bug report on the mailing list.+The git-annex behavior that causes this situation is being handled as+another bug, [[git-annex directory hashing problems on osx]].+So, closing this bug report. [[done]] --[[Joey]]
@@ -0,0 +1,32 @@+What steps will reproduce the problem?++ $ git clone ~/corbeau/travail/ travail+ Cloning into 'travail'...+ done.+ Checking out files: 100% (8670/8670), done.+ $ cd travail+ $ git annex init "portable USB drive"+ init portable USB drive + Detected a crippled filesystem.++ Enabling direct mode.++ git-annex: /media/LACIE/travail/.git/annex/objects/k1: createDirectory: already exists (File exists)+ failed+ git-annex: init: 1 failed++What version of git-annex are you using? On what operating system?+ $ apt-cache policy git-annex+ git-annex:+ Installé : 3.20130216++This on a amd64 debian sid recently updated+++Please provide any additional information below.++The problem is that git annex already created a /media/LACIE/travail/.git/annex/objects/K1 file (same name in uppercase) and FAT isn't realy case sensitive.+++> I *think* I've found the place that used createDirectory+> rather than createDirectoryIfMissing and fixed it. [[done]] --[[Joey]]
@@ -0,0 +1,34 @@+For test.com//test, I get this:++ % git annex copy . --to test.com//test+ (getting UUID for test...) git-annex: there is no git remote named "test.com//test"++And my .git/config changes from++ [remote "test.com//test"]+ url = richih@test.com:/test+ fetch = +refs/heads/*:refs/remotes/test.com//test/*++to++ [remote "test.com//test"]+ url = richih@test.com:/test+ fetch = +refs/heads/*:refs/remotes/test.com//test/*+ annex-uuid = xyz+ [remote "test"]+ annex-uuid = xyz+++Unless I am misunderstanding something, git annex gets confused about what the name of the remote it supposed to be, truncates at the dot for some operations and uses the full name for others.++> I've fixed this bug. [[done]]+> +> However, using "/" in a remote name seems likely to me to confuse +> git's own remote branch handling. Although I've never tried it.+> --[[Joey]] ++>> From what I can see, git handles / just fine, but would get upset about : which is why it's not allowed in a remote's name.+>> My naming scheme is host//path/to/annex. It sorts nicely and gives all important information left to right with the most specific parts at the beginning and end.+>> If you have any other ideas or scheme, I am all ears :)+>> Either way, thanks for fixing this so quickly.+>> -- RichiH
@@ -0,0 +1,35 @@+### Please describe the problem.++In a direct mode repo (crippled/uncrippled filesystem does not matter), when a symlink is marked using `git update-index --skip-worktree <FILE>` and removed, git annex sync still `git rm`s the symlink. This does not happen in indirect mode (git annex sync leaves the symlink in git intact).++### What steps will reproduce the problem?++[[!format sh """+mkdir test-repo; cd test-repo+git init+git annex init+echo file1 >file1+git annex add+git commit -m"update"+cd ..+git clone test-repo test-repo2; cd test-repo2+git annex init+git annex direct+git update-index --skip-worktree file1+rm file1+git annex sync+"""]]++Output of `git annex sync` indicates file has been removed from git. Repeating these steps without the `git annex direct` above to set the second repo to direct mode will succeed in retaining the symlink in git.++### What version of git-annex are you using? On what operating system?++4.20130521 using git-annex-standalone AUR build (uses Linux executable tarball) on Arch Linux++### Please provide any additional information below.++I'd like to use the skip-worktree scheme in order to be able to rm the symlink files (from the filesystem, not git), specifically for my Android devices. Syncing my music annex creates .mp3 symlinks that aren't actually MP3s, which gives the stock apps some fits. This would only be for clearing out symlinks; I fully understand that trying to doing this for downloaded content in a direct repo would be a Class A no-no. :-)++I did a little digging in the code, and it looks like the source of this is the stageDirect step done specifically by `git annex sync` in direct repos (which makes sense, since indirect repos work). It does `git ls-files --others --exclude-standard --stage`. This list includes files marked skip-worktree, which means skip-worktree files would be treated like normal, and deleted because it's no longer there. There is an additional `-t` argument that could be added to ls-files that would provide the tag field to indicate if a file was marked skip-worktree, and they could be filtered out of processing.++I wonder if this would have side effects, or if there are other places in the code where skip-worktree files would need to be handled, though. I'm particularly motivated to solve this, so let me know if it doesn't look like it would get looked at right away, and I'll have an excuse to get a Haskell dev environment setup again and shake the rust off.
@@ -0,0 +1,34 @@+What steps will reproduce the problem?++run git annex assistant, add a file, which is picked up and pushed by the assistant. ++What is the expected output? What do you see instead?++a ps -ef shows a large number of defunct git processes.. for example:+<pre>+nelg 9622 1 0 02:01 ? 00:00:01 git-annex assistant+nelg 9637 9622 0 02:01 ? 00:00:00 git --git-dir=/home/nelg/Downloads/test2/.git --work-tree=/home/nelg/Downloads/test2 cat-file --batch+nelg 12080 9622 0 02:19 ? 00:00:00 [git] <defunct>+nelg 12082 9622 0 02:19 ? 00:00:00 [git] <defunct>+nelg 12083 9622 0 02:19 ? 00:00:00 [git] <defunct>+nelg 12084 9622 0 02:19 ? 00:00:00 [git] <defunct>+-----+</pre>++What version of git-annex are you using? On what operating system?++Compiled git annex from git (cbcd208d158f8e42dda03a5eeaf1bac21045a140), on Mandriva 2010.2, 32 bit, using ghc-7.4.1.+ git version 1.7.1+++Please provide any additional information below.++I also found that the version of git I have does not support the option: --allow-empty-message+So, suggest that if the version of git installed is an older version, that the params in Assistant/Threads/Committer.hs+are changed to [ Param "-m", Param "git assistant".... or something like that.++I have done this on my copy for testing it.++For testing, I am also using two repositories on the same computer. I set this up from the command line, as the web app does not seem to support syncing to two different git folders on the same computer.++> [[done]]; all zombies are squelched now in the assistant. --[[Joey]]
@@ -14,3 +14,5 @@ Note: The problem is most likely caused by bad data from either the nntp hooks program, or the nntp server itself. I also have one file with bad data that consistently is NOT a problem for gpg to handle(lines 24-25 of log).++[[!tag moreinfo]]
@@ -0,0 +1,20 @@+Git annex refuses to get/drop files until it's manually relaunched.++I'm trying to setup a basic dropbox like system where a couple of computers sync with a local server I have constantly running ubuntu with ssh.++I think I've setup git annex correctly: when I put files in the repo folder they get uploaded to the bare git repo on the server over ssh automatically and the other computer updates with a broken alias to the file. However the file does not then download from the server despite it being available without a manual restart of the daemon or a git-annex get command from the terminal.++Additionally, files inside archive folders do not get dropped once uploaded to the server without a restart of the daemon.+++My computers are each setup with the ssh server as a 2nd repository (fullarchive), they are both OSX, and running Version: 4.20130521-g25dba9d according to the webapp. I have also entered my gmail/jabber account on each mac which I believe allows them to communicate indirectly when using the ssh repo.+++I don't know if this is a setup/misconfiguration error or a bug but I can't see how I've setup the assistant wrong, I did manually change the remote url in the config file, as the assistant was having issues connecting (I'm sshing on 21 for various reasons, although I thought this was supported and I no longer receive errors in the webapp now I've specified my remote.++Should I put the corresponding computers as a repositories of each other? I thought each syncing independently with a centralised git would be a more reliable/simple situation than a potential 3 way sync?+++I hope this is enough information, I'm usually good at working out issues myself, however this is just frustrating me and the git-annex solution is so nearly perfect if it would work reliably that I can't bring myself to give up on it!++Thanks!
@@ -0,0 +1,18 @@+### Please describe the problem.++`git annex reinject` refuses to work while in direct mode.++When in direct mode git annex reinject could simply perform `rm $symlink; mv $file_copy .; git annex add $file`. I prefer having git annex doing that so I am sure I am not messing up (mistakenly adding new files for instance) and everything is properly managed.++### What version of git-annex are you using? On what operating system?++git-annex 4.20130516.1++~~~~+$ lsb_release -a+No LSB modules are available.+Distributor ID: Ubuntu+Description: Ubuntu 12.04.2 LTS+Release: 12.04+Codename: precise+~~~~
@@ -0,0 +1,39 @@+as of git-annex version 3.20110719, all git-annex commits only contain the word "update" as a commit message. given that the contents of the commit are pretty non-descriptive (SHA1 hashes for file names, uuids for repository names), i suggest to have more descriptive commit messages, as shown here:++ /mnt/usb_disk/photos/2011$ git annex get+ /mnt/usb_disk/photos/2011$ git show git-annex+ [...]+ usb-disk-photos: get 2011+ + * 10 files retrieved from 2 sources (9 from local-harddisk, 1 from my-server)+ * 120 files were already present+ * 2 files could not be retrieved+ /mnt/usb_disk/photos/2011$ cd ~/photos/2011/07+ ~/photos/2011/07$ git copy --to my-server+ ~/photos/2011/07$ git show git-annex+ [...]+ local-harddisk: copy 2011/07 to my-server+ + * 20 files pushed+ ~/photos/2011/07$++in my opinion, the messages should at least contain++* what command was used+* in which repository they were executed+* which files or directories they affected (not necessarily all files, but what was given on command line or implicitly from the working directory)++--[[chrysn]]++> The implementation of the git-annex branch precludes more descriptive+> commit messages, since a single commit can include changes that were+> previously staged to the branch's index file, or spooled to its journal+> by other git-annex commands (either concurrently running or+> interrupted commands, or even changes needed to automatically merge+> other git-annex branches).+> +> It would be possible to make it *less* verbose, with an empty commit+> message. :) --[[Joey]] ++>> Closing as this is literally impossible to do without making+>> git-annex worse. [[done]] --[[Joey]]
@@ -16,11 +16,11 @@ * Month 8: [[!traillink Android]] * Month 9: [[screencasts|videos]] and polishing * Month 10: bugfixing, [[Android]] webapp+* Month 11: [[!traillink Windows]] porting, finishing touches We are, approximately, here: -* Month 11: [[Android]] and [[!traillink Windows]] porting-* Month 12: finishing touches+* Month 12: [presentation at SELF2013](http://www.southeastlinuxfest.org/), finishing touches ## porting
@@ -0,0 +1,14 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawlu-fdXIt_RF9ggvg4zP0yBbtjWQwHAMS4"+ nickname="Jörn"+ subject="Mount detection"+ date="2012-09-21T09:23:34Z"+ content="""+regarding the current mount polling on OSX: why not use the NSNotificationCenter for being notified on mount events on OSX?++Details see:++1. <http://stackoverflow.com/questions/12409458/detect-when-a-volume-is-mounted-on-os-x>+2. <http://stackoverflow.com/questions/6062299/how-to-add-an-observer-to-nsnotificationcenter-in-a-c-class-using-objective-c>+3. <https://developer.apple.com/library/mac/#documentation/CoreFoundation/Reference/CFNotificationCenterRef/Reference/reference.html#//apple_ref/doc/uid/20001438>+"""]]
@@ -0,0 +1,39 @@+Got the bugfix release out.++Tobias contributed [[tips/megaannex]], which allows using mega.co.nz as a+special remote. Someone should do this with Flickr, using+[filr](https://github.com/ricardobeat/filr). I have improved the+[[special_remotes/hook]] special remote to make it easier to create+and use reusable programs like megaannex.++But, I am too busy rewriting lots of the XMPP code to join in the+special remote fun. Spent all last night staring at protocol traces and+tests, and came to the conclusion that it's working well at the basic+communication level, but there are a lot of bugs above that level. This+mostly shows up as one side refusing to push changes made to its tree,+although it will happily merge in changes sent from the other side.++The NetMessanger code, which handles routing messages to git commands and+queuing other messages, seems to be just wrong. This is code I wrote in the+fall, and have basically not touched since. And it shows. Spent 4 hours+this morning rewriting it. Went all Erlang and implemented message inboxes+using STM. I'm much more confident it won't drop messages on the+floor, which the old code certainly did do sometimes.++Added a check to avoid unnecessary pushes over XMPP. Unfortunately, this+required changing the protocol in a way that will make previous versions of+git-annex refuse to accept any pushes advertised by this version. Could not+find a way around that, but there were so many unnecessary pushes happening+(and possibly contributing to other problems) that it seemed worth the+upgrade pain.++Will be beating on XMPP a bit more. There is one problem I was seeing+last night that I cannot reproduce now. It may have been masked or even+fixed by these changes, but I need to verify that, or put in a workaround.+It seemed that sometimes this code in `runPush` would run the setup+and the action, but either the action blocked forever, or an exception+got through and caused the cleanup not to be run.++[[!format haskell """+ r <- E.bracket_ setup cleanup <~> a+"""]]
@@ -0,0 +1,31 @@+Tobias has been busy again today, creating a [[/tips/flickrannex]]+special remote! Meanwhile, I'm thinking about providing a+[[more complete interface|/todo/support_for_writing_external_special_remotes]]+so that special remote programs not written in Haskell can do some of the+things the hook special remote's simplicity doesn't allow.++Finally realized last night that the main problem with the XMPP push code+was an inversion of control. Reworked it so now there are two new threads,+XMPPSendpack and XMPPReceivePack, each with their own queue of push+initiation requests, that run the pushes. This is a lot easier to+understand, probably less buggy, and lets it apply some smarts to squash+duplicate actions and pick the best request to handle next.++Also made the XMPP client send pings to detect when it has been disconnected+from the server. Currently every 120 seconds, though that may change. Testing+showed that without this, it did not notice (for at least 20 minutes) when +it lost routing to the server. Not sure why -- I'd think the TCP connections+should break and this throw an error -- but this will also handle any idle+disconnection problems that some XMPP servers might have.++While writing that, I found myself writing this jem using+[async](http://hackage.haskell.org/package/async), which has a comment+much longer than the code, but basically we get 4 threads that are all+linked, so when any dies, all do.++[[!format haskell """+pinger `concurrently` sender `concurrently` receiver+"""]]++Anyway, I need to run some long-running XMPP push tests to see if I've+really ironed out all the bugs.
@@ -0,0 +1,37 @@+The Android app should work on some more devices now, where hard linking to+busybox didn't work. Now it installs itself using symlinks.++Pushed a point release so `cabal install git-annex` works again. And,+I'm really happy to see that the 4.20130521 release has autobuilt on all+Debian architectures, and will soon be replacing the old 3.20120629 version+in testing. (Well, once a libffi transition completes..)++TobiasTheMachine has done it again: [[tips/googledriveannex]] ++-----++I spent most of today building a fuzz tester for the assistant. `git annex+fuzztest` will (once you find the special runes to allow it to run) create+random files in the repository, move them around, delete them, move+directory trees around, etc. The plan is to use this to run some long+duration tests with eg, XMPP, to make sure the assistant keeps things+in shape after a lot of activity. It logs in machine-readable format, +so if it turns up a bug I may even be able to use it to reproduce the same+bug (fingers crossed).++I was able to use QuickCheck to generate random data for some parts of the fuzz+tester. (Though the actual file names it uses are not generated using+QuickCheck.) Liked this part:++[[!format haskell """+instance Arbitrary FuzzAction where+ arbitrary = frequency+ [ (100, FuzzAdd <$> arbitrary)+ , (10, FuzzDelete <$> arbitrary)+ , (10, FuzzMove <$> arbitrary <*> arbitrary)+ , (10, FuzzModify <$> arbitrary)+ , (10, FuzzDeleteDir <$> arbitrary)+ , (10, FuzzMoveDir <$> arbitrary <*> arbitrary)+ , (10, FuzzPause <$> arbitrary)+ ]+"""]]
@@ -0,0 +1,19 @@+Got caught up on some bug reports yesterday. The main one was odd behavior+of the assistant when the repository was in manual mode. A recent change to+the preferred content expression caused it. But the expression was not+broken. The problem was in the parser, which got the parentheses wrong+in this case. I had to mostly rewrite the parser, unfortunately. I've tested+the new one fairly extensively -- on the other hand this bug lurked in the+old parser for several years (this same code is used for matching files+with command-line parameters).++Just as I finished with that, I noticed another bug. Turns out git-cat-file+doesn't reload the index after it's started. So last week's changes to make+git-annex check the state of files in the index won't work when using the+assistant. Luckily there was an easy workaround for this.++Today I finished up some robustness fixes, and added to the test suite+checks for preferred content expressions, manual mode, etc.++I've started a stress test, syncing 2 repositories over XMPP, with the fuzz+tester running in each to create lots of changes to keep in sync.
@@ -0,0 +1,12 @@+Fuzz tester has found several interesting bugs that I've now fixed. It's+even found a bug in my fixes. Most of the problems the fuzz testing has+found have had to do with direct mode merges, and automatic merge conflict+resoltion. Turns out the second level of automatic merge conflict+resolution (where the changes made to resolve a merge conflict themselves+turn out conflict in a later merge) was buggy, for example.++So, didn't really work a lot today -- was not intending to work at all+actually -- but have still accomplished a lot.++(Also, Tobias contributed [[tips/dropboxannex]] .. I'll be curious to see+what the use case for that is, if any!)
@@ -0,0 +1,12 @@+The fuzz testing found a file descriptor leak in the XMPP git push code.+The assistant seems to hold up under fuzzing for quite a while now.++Have started trying to work around some versions of Android not letting +the `am` command be used by regular users to open a web browser on an URL.+Here is my current crazy plan: Hack the terminal emulator's title setting+code, to get a new escape sequence that requests an URL be opened. This+assumes I can just use `startActivity()` from inside the app and it will+work. This may sound a little weird, but it avoids me needing to set up a+new communications channel from the assistant to the Java app. Best of all,+I have to write very little Java code. I last wrote Java code in 1995, so+writing much more is probably a good thing to avoid.
@@ -0,0 +1,19 @@+Yeah, Java hacking today. I have something that I think should deal with+the [[Android_app_permission_denial_on_startup]] problem. Added a "Open+WebApp" item to the terminal's menu, which should behave as advertised.+This is available in the Android daily build now, if your device has that+problem.++I was not able to get the escape sequence hack to work. I had no difficulty+modifying the terminal to send an intent to open an url when it received a+custom escape sequence. But sending the intent just seemed to lock up the+terminal for a minute without doing anything. No idea why. I had to propigate a+context object in to the terminal emulator through several layers of objects.+Perhaps that doesn't really work despite what I [read on stackoverflow](http://stackoverflow.com/questions/9051849/opening-a-link-in-the-browser/9052208#9052208).++Anyway, that's all I have time to do. It would be nice if I, or some other+interested developer who is more comfortable with Java, could write a custom+Android frontend app, that embedded a web browser widget for the webapp,+rather than abusing the terminal this way. OTOH, this way does provide the+bonus of a pretty good terminal and git shell environment for Android to go+with git-annex.
@@ -0,0 +1,11 @@+Winding down work for now, as I prepare for a week at the beach starting in+2 days. That will be followed by a talk about git-annex at+[SELF2013](http://www.southeastlinuxfest.org/) in Charlotte NC on June 9th.++Bits & pieces today.++Want to get a release out RSN, but I'm waiting for the previous release+to finally reach Debian testing, which should happen on Saturday. Luckily I+hear the beach house has wifi, so I will probably end up cutting the+release from there. Only other thing I might work on next week is updating+to yesod 1.2.
@@ -0,0 +1,14 @@+Landed two final changes before the release..++First, made git-annex detect if any of the several long-running git process+it talks to have died, and, if yes, restart them. My stress test is reliably+able to get at least `git cat-file` to crash, and while I don't know why (and+obviously should follow up by getting a core dump and stack trace of it),+the assistant needs to deal with this to be robust.++Secondly, wrote rather a lot of Java code to better open the web browser+when the Android app is started. A thread listens for URLs to be written to+a FIFO. Creating a FIFO from fortran^Wjava code is .. interesting. Glad to+see the back of the `am` command; it did me no favors.++AFK
@@ -0,0 +1,34 @@+It's possible for one git annex repository to configure a special remote+that it makes sense for other repositories to also be able to use. Today I+added the UI to support that; in the list of repositories, such+repositories have a "enable" link.++To enable pre-existing rsync special remotes, the webapp has to do the same+probing and ssh key setup that it does when initially creating them.+Rsync.net is also handled as a special case in that code. There was one+ugly part to this.. When a rsync remote is configured in the webapp,+it uses a mangled hostname like "git-annex-example.com-user", to+make ssh use the key it sets up. That gets stored in the `remote.log`, and so+the enabling code has to unmangle it to get back to the real hostname.++---++Based on the still-running [[prioritizing_special_remotes]] poll, a lot+of people want special remote support for their phone or mp3 player.+(As opposed to running git-annex on an Android phone, which comes later..)+It'd be easy enough to make the webapp set up a directory special remote+on such a device, but that makes consuming some types of content on the+phone difficult (mp3 players seem to handle them ok based on what people tell+me). I need to think more about some of the ideas mentioned in [[android]]+for more suitable ways of storing files.++One thing's for sure: You won't want the assistant to sync all your files+to your phone! So I also need to start coming up with partial syncing+controls. One idea is for each remote to have a configurable matcher for files+it likes to receive. That could be only mp3 files, or all files inside a+given subdirectory, or all files *not* in a given subdirectory. That means+that when the assistant detects a file has been moved, it'll need to add+(or remove) a queued transfer. Lots of other things could be matched on,+like file size, number of copies, etc. Oh look, I have a+[beautiful library I wrote earlier](http://joeyh.name/blog/entry/happy_haskell_hacker)+that I can reuse!
@@ -15,7 +15,8 @@ REST API; free software * Mediafire provides 50gb free and has a REST API. * Flickr provides 1 tb (!!!!) to free accounts, and can store at least- photos and videos.+ photos and videos. <https://github.com/ricardobeat/filr> is a hack+ to allow storing any type of file on Flickr. * mega.co.nz. Already supported via [[tips/megaannex]], would just need webapp modifications to configure it. May want to use megaannex as-is to build a non-hook special remote in haskell.
@@ -4,4 +4,4 @@ want the first time they run it, but to save typing on android, anything that gets enough votes will be included in a list of choices as well. -[[!poll open=yes expandable=yes 45 "/sdcard/annex" 3 "Whole /sdcard" 4 "DCIM directory (photos and videos only)" 1 "Same as for regular git-annex. ~/annex/"]]+[[!poll open=yes expandable=yes 47 "/sdcard/annex" 3 "Whole /sdcard" 4 "DCIM directory (photos and videos only)" 1 "Same as for regular git-annex. ~/annex/"]]
@@ -4,11 +4,11 @@ ### TODO -* Prevent idle disconnection. Probably means sending or receiving pings,- but would prefer to avoid eg pinging every 60 seconds as some clients do. * Do git-annex clients sharing an account with regular clients cause confusing things to happen? See <http://git-annex.branchable.com/design/assistant/blog/day_114__xmpp/#comment-aaba579f92cb452caf26ac53071a6788>+* Support registering with XMPP provider from within the webapp, + as clients like pidgin are able to do. ## design goals @@ -66,8 +66,12 @@ To indicate that we could push over XMPP, a chat message is sent, to each known client of each XMPP remote. - <git-annex xmlns='git-annex' canpush="myuuid" />+ <git-annex xmlns='git-annex' canpush="myuuid" shas="sha1 sha1" /> +The shas are omitted by old clients. If present, they are the git shas of+the head and git-annex branches that are available to be pushed. This lets+the receiver check if it's already got them.+ To request that a remote push to us, a chat message can be sent. <git-annex xmlns='git-annex' pushrequest="myuuid" />@@ -96,8 +100,7 @@ The value of rp and sp used to be empty, but now it's a sequence number. This indicates the sequence of this packet, counting from 1. The receiver-and sender each have their own sequence numbers. These sequence numbers-are not really used yet, but are available for debugging.+and sender each have their own sequence numbers. When `git receive-pack` exits, the receiver indicates its exit status with a chat message, directed at the sender:
@@ -0,0 +1,68 @@+Hi everyone,++everyday I understand more and more how git and git-annex work but I need help with this one.+I guess I have two questions but let me describe the scenario first:++I have one local repository of mp3s (assume just one file: file1.mp3).+I clone that repository into a remote git-annex repository over ssh and "git annex get" the file contents for file1.mp3.++I unlock some mp3's locally and modify some mp3 tags. +Then I notify git-annex of these changes+with "git annex add *"+and commit them with "git commit -m 'mp3 tags changed'". +[git annex locks them again and changes the symlinks to point to the changed file in the annex, git commits the changed symlink]++At this point in time there are two objects in my git annex repository:+hash(file1.mp3) +hash(file1.mp3|with modified tags)+The symlink points now to hash(file1.mp3|with modified tags)++At this point the remote still does not now of this commit and of the new file contents.+Thus I do "git push" to send the changes to the remote.+The remote now has a BROKEN symlink because it already points to hash(file1.mp3|with modified tags)+but the remote annex's object directory only contains hash(file1.mp3).++Then I want my remote repository to also have the updated mp3 tags.+The only way I see (without scripting) to have the updated mp3 tags in the remote repository is to do an "git annex get file1.mp3" on the remote repository or an "git annex copy --to remote file1.mp3" at my local repository. However, although the binary differences between both files+file1.mp3 and file1.mp3|with modified tags are small the latter is transferred completely from the local repository to the remote repository.++This is not a problem when just changing one file, but a problem when I have 10GB's of files and when it takes 2days to upload them to the remote because of a low bandwidth. ++First question: Did I miss something? Does git-annex already provide means to only transmit the diff between the two objects? ++Second question regarding disk space.+I now have a complete history of all changes to file1.mp3 in my git-annex repository. I have the objects that represent every state of file1.mp3 and I can go back to these states when I checkout the respective commits and thereby the symlinks that link to these "old" objects. This history can take up a lot of space. What is the clean way to forget the past? AFAIK "git drop unused" only drops file contents that are not referenced in any commit? ++If one wanted to preserve the entire history but save disk space one could also only store the current content and the patches that allow to reconstruct older versions from the current one. I understand that applying several patches consecutively takes more cpu time but for me going back to an older commit with my binary files only happens rarely. ++This is the algorithm I have in mind for an optimized "git annex get file1":++On that repository where the file is missing:++1. Find the newest object that represented the contents of file1 in file1's commit history.++2. Transmit this object identification hash(object) to the remote that has the current version (the one I am getting from).++At that remote: ++If the history contains full versions of file contents:++Create a binary diff between the object identified by hash(object) and the current content of file1.++If the history contains only the current version and patches to older versions:+Collect all patches that represent the change from hash(object) to the current content of file1.++If the list of patches is bigger than the current content of file 1 transmit the current content of file1. Otherwise transmit the patch(es) ++On that repository where the file is missing:++Apply the patch(es) to the latest object to obtain the current object.++What's your opinion on this?++Marek+++++
@@ -0,0 +1,9 @@+I have a repository on my laptop with a single remote on a USB drive. Both were created without the assistant.++The remote holds all the content. My understanding is that this would be a "backup" repository, using the group definitions.++The local repository generally holds no content. When I want a file, I make sure the remote is available, and then I `git annex get` it.++This works fine in git annex, but I'm now experimenting with the assistant. As soon as I fire up the assistant, it starts downloading all of the data from the remote. I don't ever want it to automatically get any content from the remote. If it sees new content in the repository, I would like it to push that out to the remote. But never get anything from the remote, and never drop anything that is in the repository.++How can I setup this behaviour in the assistant? I have set the remote's repository group to "backup". The local repository is not in any group, since none of the groups fit my model for this repo.
@@ -0,0 +1,3 @@+Hi, I'd like to share files with friends, to do so we need a shared server to exchange the files. I could setup an ssh access on one of my servers but I don't want others to have a full access. I assume I can restrict this using a `command='wrapper-around-git'` prefix in `.ssh/authorized_keys`, where `wrapper-around-git` is simply a script that checks if `SSH_ORIGINAL_COMMAND` is an authorised command and runs it. This is exactly the approach used with Mercurial (hg-ssh) and presumably git also relies on this mechanism.++But to do so, I need to know what commands can be executed over ssh when using git-annex assistant. Could you document about this? Thanks!
@@ -0,0 +1,11 @@+Hello Joey,++I just want to know if file transfers between three inter-connected repositories somehow gets syncronized. I have a laptop, a local file server in my home and a virtual server on the internet.++Both my laptop and my file server are configured with a full git repository and connected through pairing and xmpp. The server on the internet is configured as a rsync special remote.++I want the local file server to hold a copy of everything in my annex, the rsync remote should get everything except the folder "media" (too large to upload and not that important) and the laptop whatever I manually decide (preferred content is set to "present").++I have added some files to the repository on the local file server and transferred their content to my laptop by using "git annex get". But when I started the web interface, I saw that those files who are present on both the file server and on the laptop get uploaded to the remote server from both computers, often the same file at the same time. Previously I though the two assistants would somehow talk to each other via xmpp so that doubled effort like that would be avoided. I'm also worried about data consistency because two apparently separate processes rsync to the same remote repository at the same time.++So my question would be: Is your xmpp protocol designed to deal with situations like this and I did not set it up correctly or is what I'm trying to accomplish simply not (yet) possible?
@@ -0,0 +1,3 @@+I have a question on setting up a new repo. Is it possible to initialize a new repo using files which are already local on say my laptop, instead of downloading them from a S3 remote repository? Sorry if this is unclear. But I'm trying to make use of the files that are local on my laptop so I don's have to go through the ordeal of downloading them from S3.++I should also mention that I don't have a complete set of all the files locally on the laptop vs. what's already in the S3 repository.
@@ -0,0 +1,27 @@+Hi,++this is not a git-annex problem, but more likely a way some software handles symlinks and/or do file-type detection.++my setup is a following:+- multiple pc/laptop (linux)+- one NAS (debian) - main repo for music/films/photos - all in git-annex+- a Raspberry Pi (Raspbmc) - connected to the TV++I want to share all my films/music/.. to the Pi.+So, i setup a r/o NFS and mounted that in the XBMC.+So far this works, I see directories but XBMC do not recognize the media files.+It works, if I "git-annex edit ..." the file.++My _assumption_ is, that it follows the symlink, finds a file with no extension - and ignores that.+In XBMC-config there is a list of supported filetypes by extension. ( .avi,.mpg,.foo,.bar )++What I have think of so far:+- tell XBMC somehow to load all the files (did not work)+- having some kind of (FUSE?) filter, which hides the symlink in a transparent way+- creating via script hard-links in a seperate folder with same structure, mount that.+- using some alternative to NFS ( like ftp, smb ) or a other kind of media-server (server-side)++any comments, ideas ? +If i find a solution, I'll post it here.++.ka
@@ -0,0 +1,7 @@+flickrannex -- is it a way to upload your images to flickr by putting them in a git annex directory, and make them retrievable from it handily that way?++Or is it a hack to exploit flickr's free storage, by allowing you to somehow wrap your files in images and uploading them?++My python and knowledge of how git annex's hooks work is not good enough for me to be certain by reading the code.++Thanks
@@ -0,0 +1,6 @@+I propose to add some functionality to git-annex, to automatically "throttle" the data retrieval from amazon glacier to stay within the daily free retrieval allowance. If someone would need to get his/her files faster, there should be an option to disable this throttling (or even better, specify the retrieval rate).++As far as I understand glacier, this could be implemented using range retrievals. In short range retrievals enable you, to only retrieve a part of an archive in glacier. This can be used to only retrieve / request so much data, that you stay within the free retrieval allowance. ( please see [Q: Why would I retrieve only a range of an archive?](http://aws.amazon.com/glacier/faqs/#Why_would_I_retrieve_only_a_range_of_an_archive) ).+++This would be somewhat similar to the [smart retrieval feature in cloudberry](http://blog.cloudberrylab.com/2012/12/introducing-smart-restore-for-amazon.html) .
@@ -0,0 +1,12 @@+## Question+Can git-annex run passively with an existing repo?++## Scenario+We have an existing web application with large binary assets spread throughout modules in the repo. The project is in constant development with weekly deploys to production and there are many developers working on the project.++## Goal+We need to maintain the directory structure for these assets without actually committing large binaries to the main remote (hosted on GitHub). I need a solution that has a low barrier of entry when on-boarding new developers. I was thinking maybe a script the is executed on every commit that would filter binaries files based on extensions and commit them to the git-annex remote instead. We are flexible on the type of remote storage type (SSH, S3, etc)++## Notes+I have gone through the last couple months of forum posts and done a bit of Googling but have come up empty. If anyone can point me in the right direction that would be great. +Thanks!
@@ -0,0 +1,3 @@+A couple times working in an annex manually, I accidentally did "git add" instead of "git annex add" and ended up with files checked into my repo instead of symlinks. So now there is some file content in git, rather than in the annex. Is there any way to root that out, or is it there forever? (My limited knowledge of git says: it's there forever, unless maybe you go into the branches where it lives, do an interactive rebase to the time before it was added, remove that commit, replay history, and then garbage collect, but I have no idea if that would suddenly break git annex, and it sounds painful anyway.)++If say I were a neat freak and wanted to just start over with a clean annex, I imagine the thing to do would be to just start the hell over -- and if I wanted to do that, the way to go would be to get into a full repository, do a "git annex uninit" and then throw away the .git directory, then do "git init" and "git annex init" and then "git annex add ." ?
@@ -0,0 +1,3 @@+Currently I have my netbook running git annex and a raspberry pi as a remote storage set up as a git repository. I currently have it set up so that from the terminal i can just do 'ssh pi@mypi -p XXX -C' and it has the password saved. Currently I'm having a problem that any time I add a file to my annex folder on my netbook I have to reenter my password for ssh-askpass for it to upload the file. Once that file is uploaded, it looks to me like it closes the connection and then reopens it and asks for my password again.++I'm looking in ~/.ssh/ and I'm sure that something there needs to be edited or copied, I'm not really sure what though. Any suggestions?
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="http://a-or-b.myopenid.com/"+ ip="203.45.2.230"+ subject="comment 1"+ date="2013-05-30T00:08:52Z"+ content="""+It sounds like you don't have the ssh-agent set up properly in your environment.++Try starting the git annex agent from the command line and see if that helps. If it works then it is a problem with environment variables.+"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ nickname="joey"+ subject="comment 2"+ date="2013-05-30T15:49:27Z"+ content="""+If you set this repository up using the git-annex webapp, and choosing \"remote ssh server\", it will generate a new ssh key, stored in `~/.ssh/git-annex/`, and it will configure `~/.ssh/config` to use this key for a special made-up hostname which is used in the url for the git remote. On the server, it will set up `~/.ssh/authorized_keys` to allow this ssh key to connect without a password and run git-annex-shell.++I don't know if you used the webapp to set this up. If not, you can try to replicate this setup on your own. If you did and it's not working, you now know where all the peices it sets up are, to figure out what went wrong.+"""]]
@@ -0,0 +1,2 @@+Is that really unsafe? Because I did that and the switch to direct mode seemed to leave a lot of files still as links, and when I panicked and switched back to indirect mode, a whole lot of stuff seemed to have become unannexed and I reannexed it.+
@@ -2,7 +2,7 @@ years, you'd like its contents to be as accessible as possible to whoever digs it up. -This is a hard problem. git-annex cannot completly solve it, but it does+This is a hard problem. git-annex cannot completely solve it, but it does its best to not contribute to the problem. Here are some aspects of the problem:
@@ -247,6 +247,11 @@ (or encryption=emailaddress) to specify a gpg key that can access the encrypted special remote. + Note that with encryption enabled, a gpg key is created. This requires+ sufficient entropy. If initremote seems to hang or take a long time+ while generating the key, you may want to ctrl-c it and re-run with --fast,+ which causes it to use a lower-quality source of randomness.+ Example Amazon S3 remote: git annex initremote mys3 type=S3 encryption=me@example.com datacenter=EU@@ -300,6 +305,14 @@ * ungroup repository groupname Removes a repository from a group.++* content repository [expression]++ When run with an expression, configures the content that is preferred+ to be held in the archive. See PREFERRED CONTENT below.++ Without an expression, displays the current preferred content setting+ of the repository. * vicfg
@@ -0,0 +1,12 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ nickname="joey"+ subject="comment 10"+ date="2013-05-30T19:42:05Z"+ content="""+As of today, I have backported everything except for haskell-lens, haskell-dav, and haskell-network-protocol-xmpp. The last is the only real blocker (I can build a backport without webdav support..). ++The haskell-network-protocol-xmpp in stable is actually ok, except it needs to be rebuilt against the haskell-gnutls I uploaded today. This fixes a bad segfault bug. I don't know how to handle this situation in backports TBH, and so am stuck waiting for a newer version of haskell-network-protocol-xmpp to reach testing, to get around backport's requirements that the backport version be in testing.++In other words, it'll happen in 2 to 5 weeks, probably..+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://hands.com/~phil/"+ nickname="hands"+ subject="comment 11"+ date="2013-05-30T19:56:07Z"+ content="""+Fair enough -- that's more positive than I was expecting TBH -- Thanks Joey :-)+"""]]
@@ -0,0 +1,12 @@+[[!comment format=mdwn+ username="http://mey.vn/"+ ip="46.65.14.106"+ subject="libc6 dep version on amd64"+ date="2013-05-28T15:28:47Z"+ content="""+hi Joey,++i see from the release notes of the 4.20130521 release that the Debian package should now be built with libc6 2.13, which appears to be the case except for the amd64 arch (hence the amd64 package won't install as is on Wheezy on amd64) - is this a build glitch or is 2.14 needed on amd64 (i imagine as a dependency of one of git-annex's deps on that arch)?++thanks!+"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ nickname="joey"+ subject="comment 8"+ date="2013-05-29T16:23:10Z"+ content="""+@mey.vn, Debian packages of git-annex, as uploaded to the Debian repositories, are built with whatever libc version the Debian autobuilder is running. You cannot, in general, install packages from Debian unstable into stable without upgrading your libc6.++The release notes were not talking about the Debian packages, but about the [[Linux_standalone]] tarballs. Those are built with libc 2.13.+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://hands.com/~phil/"+ nickname="hands"+ subject="any chance of a wheezy-backports upload?"+ date="2013-05-30T18:43:52Z"+ content="""+I note that the instructions at the top of the page suggest that one can install the unstable version into wheezy, but as mentioned by [mey.vn](#comment-f9811cbd46471d4159d09d814ac9cf15) this is not the case with 4.20130521 (on amd64 at least) because of the libc6 version dependency. That being the case, it would be really nice to see this in wheezy-backports as well, or would that require backporting a huge pile of haskell as well? (in which case I can see why you're not keen).+"""]]
@@ -40,6 +40,7 @@ brew link libxml2 cabal update PATH=$HOME/bin:$PATH+cabal install gnuidn cabal install c2hs git-annex --bindir=$HOME/bin </pre>
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawlQ7ZdQxAps4v0cl5J3wKGWD8243Gy8-m0"+ nickname="Phil"+ subject="PPA Package Pinning"+ date="2013-05-23T21:18:14Z"+ content="""+@Pedro, see <http://askubuntu.com/a/170265> for blocking all packages except git-annex from François's repo.+"""]]
@@ -13,7 +13,7 @@ A daily build is also available, thanks to Yury V. Zaytsev and [NEST](http://nest-initiative.org/). -* [download](https://qa.nest-initiative.org/view/msysGit/job/msysgit-git-annex-assistant-test/lastSuccessfulBuild/artifact/git-annex-installer.exe) ([build logs](https://qa.nest-initiative.org/view/msysGit/job/msysgit-git-annex-assistant-test/))+* [download](https://qa.nest-initiative.org/view/msysGit/job/msysgit-git-annex-assistant-test/lastSuccessfulBuild/artifact/git-annex/git-annex-installer.exe) ([build logs](https://qa.nest-initiative.org/view/msysGit/job/msysgit-git-annex-assistant-test/)) ## building it yourself
@@ -5,7 +5,8 @@ cabal update PATH=$HOME/bin:$PATH- cabal install c2hs git-annex --bindir=$HOME/bin+ cabal install c2hs+ cabal install git-annex --bindir=$HOME/bin The above downloads the latest release and installs it into a ~/bin/ directory, which you can put in your PATH.@@ -20,3 +21,11 @@ cabal configure cabal build cabal install --bindir=$HOME/bin++By default, cabal will try to build git-annex with the git-annex assistant+and webapp. This requires several C libraries and their headers be already+installed on your system, including libgnutls, libgsasl, libxml2, and zlib.+To build git-annex without the assistant and webapp, you can pass flags to+cabal install. For example:++ cabal install git-annex --flags="-assistant -WebApp" --bindir=$HOME/bin
@@ -0,0 +1,17 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawnaH44G3QbxBAYyDwy0PbvL0ls60XoaR3Y"+ nickname="Nigel"+ subject="E: Unable to locate package libghc-libxml-sax-dev"+ date="2013-05-30T15:05:47Z"+ content="""+I get an error from the command as above:+$ sudo apt-get install cabal-install libgnutls28-dev libgsasl7-dev c2hs libghc libxml-sax-dev zlib1g-dev libghc-zlib-dev++$ lsb_release -a+No LSB modules are available.+Distributor ID: Ubuntu+Description: Ubuntu 12.04.2 LTS+Release: 12.04+Codename: precise++"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ nickname="joey"+ subject="comment 3"+ date="2013-05-30T15:25:29Z"+ content="""+If you're installing git-annex with cabal, there is no need to install any haskell library packages with apt-get. That includes libghc-libxml-sax-dev and libghc-zlib-dev. Without those, the apt-get line may work to install the C libraries needed for cabal to install the haskell libraries. ++However, see the the [[Ubuntu]] page for much easier ways to get git-annex installed.+"""]]
@@ -0,0 +1,14 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawnaH44G3QbxBAYyDwy0PbvL0ls60XoaR3Y"+ nickname="Nigel"+ subject="Re: Comment 3"+ date="2013-05-30T15:48:44Z"+ content="""+@Joey Many thanks.+I am new to Haskell (vaguely looked at it with DARCS) and git-annex.+After installing with apt-get on Ubuntu 12.04 LTS I found webapp was missing, hence have come here.+I am going through the correct steps now, it should be awesome when done.++This seems to be a long build process (still going on my old laptop, much longer than apt-get).+Ubuntu git-annex packages from 13.10 Saucy I think are updated to include webapp.+"""]]
@@ -0,0 +1,24 @@+[[!comment format=txt+ username="https://www.google.com/accounts/o8/id?id=AItOawnaH44G3QbxBAYyDwy0PbvL0ls60XoaR3Y"+ nickname="Nigel"+ subject="Re: Comment 3"+ date="2013-05-30T16:29:12Z"+ content="""+At the end of the build I got these errors:+Registering yesod-static-1.1.2.3...+Installing library in /home/nrb/.cabal/lib/yesod-static-1.1.2.3/ghc-7.4.1+Registering yesod-static-1.1.2.3...+cabal: Error: some packages failed to install:+c2hs-0.16.4 depends on language-c-0.3.2.1 which failed to install.+dbus-0.10.4 depends on libxml-sax-0.7.4 which failed to install.+git-annex-4.20130521.2 depends on libxml-sax-0.7.4 which failed to install.+language-c-0.3.2.1 failed during the configure step. The exception was:+ExitFailure 1+libxml-sax-0.7.4 failed during the configure step. The exception was:+ExitFailure 1+network-protocol-xmpp-0.4.5 depends on libxml-sax-0.7.4 which failed to+install.++One way I could fix this myself is to put together a VM with 13.10 or Debian in it and work inside that.+Or if I can get help to fix my issues here that would be great ;)+"""]]
@@ -0,0 +1,21 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawnaH44G3QbxBAYyDwy0PbvL0ls60XoaR3Y"+ nickname="Nigel"+ subject="Some errors after the build"+ date="2013-05-30T16:38:37Z"+ content="""+ Registering yesod-static-1.1.2.3...+ Installing library in /home/nrb/.cabal/lib/yesod-static-1.1.2.3/ghc-7.4.1+ Registering yesod-static-1.1.2.3...+ cabal: Error: some packages failed to install:+ c2hs-0.16.4 depends on language-c-0.3.2.1 which failed to install.+ dbus-0.10.4 depends on libxml-sax-0.7.4 which failed to install.+ git-annex-4.20130521.2 depends on libxml-sax-0.7.4 which failed to install.+ language-c-0.3.2.1 failed during the configure step. The exception was:+ ExitFailure 1+ libxml-sax-0.7.4 failed during the configure step. The exception was:+ ExitFailure 1+ network-protocol-xmpp-0.4.5 depends on libxml-sax-0.7.4 which failed to+ install.++"""]]
@@ -1,37 +0,0 @@-git-annex 4.20130323 released with [[!toggle text="these changes"]]-[[!toggleable text="""- * webapp: Repository list is now included in the dashboard, and other- UI tweaks.- * webapp: Improved UI for pairing your own devices together using XMPP.- * webapp: Display an alert when there are XMPP remotes, and a cloud- transfer repository needs to be configured.- * Add incrementalbackup repository group.- * webapp: Encourage user to install git-annex on a server when adding- a ssh server, rather than just funneling them through to rsync.- * xmpp: --debug now enables a sanitized dump of the XMPP protocol- * xmpp: Try harder to detect presence of clients when there's a git push- to send.- * xmpp: Re-enable XA flag, since disabling it did not turn out to help- with the problems Google Talk has with not always sending presence- messages to clients.- * map: Combine duplicate repositories, for a nicer looking map.- * Fix several bugs caused by a bad Ord instance for Remote.- * webapp: Switch all forms to POST.- * assistant: Avoid syncing with annex-ignored remotes when reconnecting- to the network, or connecting a drive.- * assistant: Fix OSX bug that prevented committing changed files to a- repository when in indirect mode.- * webapp: Improved alerts displayed when syncing with remotes, and- when syncing with a remote fails.- * webapp: Force wrap long filenames in transfer display.- * assistant: The ConfigMonitor left one zombie behind each time- it checked for changes, now fixed.- * get, copy, move: Display an error message when an identical transfer- is already in progress, rather than failing with no indication why.- * assistant: Several optimisations to file transfers.- * OSX app and standalone Linux tarball now both support being added to- PATH; no need to use runshell to start git-annex.- * webapp: When adding a removable drive, you can now specify the- directory inside it to use.- * webapp: Confirm whether user wants to combine repositories when- adding a removable drive that already has a repository on it."""]]
@@ -1,34 +0,0 @@-git-annex 4.20130405 released with [[!toggle text="these changes"]]-[[!toggleable text="""- * Group subcommands into sections in usage. Closes: #[703797](http://bugs.debian.org/703797)- * Per-command usage messages.- * webapp: Fix a race that sometimes caused alerts or other notifications- to be missed if they occurred while a page was loading.- * webapp: Progess bar fixes for many types of special remotes.- * Build debian package without using cabal, which writes to HOME.- Closes: #[704205](http://bugs.debian.org/704205)- * webapp: Run ssh server probes in a way that will work when the- login shell is a monstrosity that should have died 25 years ago,- such as csh.- * New annex.largefiles setting, which configures which files- `git annex add` and the assistant add to the annex.- * assistant: Check small files into git directly.- * Remotes can be configured to use other MAC algorithms than HMACSHA1- to encrypt filenames.- Thanks, guilhem for the patch.- * git-annex-shell: Passes rsync --bwlimit options on rsync.- Thanks, guilhem for the patch.- * webapp: Added UI to delete repositories. Closes: #[689847](http://bugs.debian.org/689847)- * Adjust built-in preferred content expressions to make most types- of repositories want content that is only located on untrusted, dead,- and unwanted repositories.- * drop --auto: Fix bug that prevented dropping files from untrusted- repositories.- * assistant: Fix bug that could cause direct mode files to be unstaged- from git.- * Update working tree files fully atomically.- * webapp: Improved transfer queue management.- * init: Probe whether the filesystem supports fifos, and if not,- disable ssh connection caching.- * Use lower case hash directories for storing files on crippled filesystems,- same as is already done for bare repositories."""]]
@@ -0,0 +1,24 @@+git-annex 4.20130521 released with [[!toggle text="these changes"]]+[[!toggleable text="""+ * Sanitize debian changelog version before putting it into cabal file.+ Closes: #[708619](http://bugs.debian.org/708619)+ * Switch to MonadCatchIO-transformers for better handling of state while+ catching exceptions.+ * Fix a zombie that could result when running a process like gpg to+ read and write to it.+ * Allow building with gpg2.+ * Disable building with the haskell threaded runtime when the webapp+ is not built. This may fix builds on mips, s390x and sparc, which are+ failing to link -lHSrts\_thr+ * Temporarily build without webapp on kfreebsd-i386, until yesod is+ installable there again.+ * Direct mode bug fix: After a conflicted merge was automatically resolved,+ the content of a file that was already present could incorrectly+ be replaced with a symlink.+ * Fix a bug in the git-annex branch handling code that could+ cause info from a remote to not be merged and take effect immediately.+ * Direct mode is now fully tested by the test suite.+ * Detect bad content in ~/.config/git-annex/program and look in PATH instead.+ * OSX: Fixed gpg included in dmg.+ * Linux standalone: Back to being built with glibc 2.13 for maximum+ portability."""]]
@@ -0,0 +1,25 @@+git-annex 4.20130601 released with [[!toggle text="these changes"]]+[[!toggleable text="""+ * XMPP: Git push over xmpp made much more robust.+ * XMPP: Avoid redundant and unncessary pushes. Note that this breaks+ compatibility with previous versions of git-annex, which will refuse+ to accept any XMPP pushes from this version.+ * XMPP: Send pings and use them to detect when contact with the server+ is lost.+ * hook special remote: Added combined hook program support.+ * Android app: Avoid using hard links to app's lib directory, which+ is sometimes on a different filesystem than the data directory.+ * Fix bug in parsing of parens in some preferred content expressions.+ This fixes the behavior of the manual mode group.+ * assistant: Work around git-cat-file's not reloading the index after files+ are staged.+ * Improve error handling when getting uuid of http remotes to auto-ignore,+ like with ssh remotes.+ * content: New command line way to view and configure a repository's+ preferred content settings.+ * sync: Fix double merge conflict resolution handling.+ * XMPP: Fix a file descriptor leak.+ * Android: Added an "Open WebApp" item to the terminal's menu.+ * Android: Work around Android devices where the `am` command doesn't work.+ * Can now restart certain long-running git processes if they crash, and+ continue working."""]]
@@ -6,10 +6,10 @@ this allows `git annex get --auto`, `git annex drop --auto`, etc to do smarter things. -Currently, preferred content settings can only be edited using `git-annex vicfg`. Each repository can have its own settings, and other-repositories may also try to honor those settings. So there's no local-`.git/config` setting it.+Preferred content settings can be edited using `git+annex vicfg`, or viewed and set at the command line with `git annex content`.+Each repository can have its own settings, and other repositories may also+try to honor those settings. So there's no local `.git/config` setting it. The idea is that you write an expression that files are matched against. If a file matches, it's preferred to have its content stored in the
@@ -21,14 +21,18 @@ into many cloud services. Here are specific instructions for various cloud things: -* [[tips/using_Amazon_S3]]-* [[tips/using_Amazon_Glacier]]+* [[Amazon_S3|tips/using_Amazon_S3]]+* [[Amazon_Glacier|tips/using_Amazon_Glacier]] * [[tips/Internet_Archive_via_S3]] * [[tahoe-lafs|forum/tips:_special__95__remotes__47__hook_with_tahoe-lafs]]-* [[tips/using_box.com_as_a_special_remote]]-* [[tips/using_mega.co.nz_as_a_special_remote|tips/megaannex]]-* [[forum/special_remote_for_IMAP]]-* [[forum/nntp__47__usenet special remote]]+* [[Box.com|tips/using_box.com_as_a_special_remote]]+* [[Google drive|tips/googledriveannex]]+* [[Google Cloud Storage|tips/using_Google_Cloud_Storage]]+* [[Mega.co.nz|tips/megaannex]]+* [[SkyDrive|tips/skydrive]]+* [[Flickr|tips/flickrannex]]+* [[IMAP|forum/special_remote_for_IMAP]]+* [[Usenet|forum/nntp__47__usenet special remote]] ## Unused content on special remotes
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ nickname="joey"+ subject="comment 10"+ date="2013-05-23T20:04:03Z"+ content="""+You can enable a special remote on a clone by running `git annex enableremote $name`, where $name is the name you used to originally create the special remote. (Older versions of git-annex used `git annex initremote` to enable the special remote on the clone.)++(Just in case, I have verified that embedcreds does cause the cipher= to be stored in the remote.log. It does.)+"""]]
@@ -0,0 +1,12 @@+[[!comment format=mdwn+ username="basak"+ ip="2001:8b0:1c8::2"+ subject="comment 11"+ date="2013-05-24T09:38:40Z"+ content="""+Thanks Joey - initremote on my slightly older version appears to work. I'll use `enableremote` when I can.++> (Just in case, I have verified that embedcreds does cause the cipher= to be stored in the remote.log. It does.)++This doesn't do what I expect. The documentation suggests that my S3 _login_ credentials would be stored. I understand that the cipher would be stored; but isn't this a separate concept? Instead, I'm being asked to set `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`; my understanding was that git-annex will keep them in the repository for me, so that I don't have to set them after running `initremote` before cloning. This works, apart from surviving the cloning. I'm using `encryption=shared`; does this affect anything? Or am I using a version of git-annex (3.20121112ubuntu3) that's too old?+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ nickname="joey"+ subject="comment 12"+ date="2013-05-24T15:33:12Z"+ content="""+Ah -- No, your AWS creds are not stored. While some other special remotes, like webdav, can store all necessary credentials, it's not done for AWS. I didn't want git-annex to be responsible for someone accidentially publishing their AWS creds to their friends, since that could cost them a lot of money.+"""]]
@@ -0,0 +1,33 @@+[[!comment format=mdwn+ username="basak"+ ip="2001:8b0:1c8::2"+ subject="comment 13"+ date="2013-05-24T15:47:14Z"+ content="""+That's not what the documentation here says! It even warns me: \"Think carefully about who can access your repository before using embedcreds without gpg encryption.\"++My use case:++Occasional use of EC2, and a desire to store some persistent stuff in S3, since the dataset is large and I have limited bandwidth. I want to destroy the EC2 instance when I'm not using it, leaving the data in S3 for later.++If I use git-annex to manage the S3 store, then I get the ability to clone the repository and destroy the instance. Later, I can start a new instance, push the repo back up, and would like to be able to then pull the data back out of S3 again.++I'd really like the login credentials to persist in the repository (as the documentation here says it should). Even if I have to add a --yes-i-know-my-s3-credentials-will-end-up-available-to-anyone-who-can-see-my-git-repo flag. This is because I use some of my git repos to store private data, too.++If I use an Amazon IAM policy as follows, I can generate a set of credentials that are limited to access to a particular prefix of a specific S3 bucket only - effectively creating a sandboxed area just for git-annex:++ { + \"Statement\": [{\"Sid\": \"Stmt1368780615583\",+ \"Action\": [\"s3:GetObject\", \"s3:PutObject\", \"s3:DeleteObject\"],+ \"Effect\": \"Allow\",+ \"Resource\": [\"arn:aws:s3:::bucketname/prefix/*\"]}+ ],+ \"Statement\": [{\"Sid\": \"Stmt1368781573129\",+ \"Action\": [\"s3:GetBucketLocation\"],+ \"Effect\": \"Allow\",+ \"Resource\": [\"arn:aws:s3:::bucketname\"]}+ ]+ }++Doing this means that I have a different set of credentials for every annex, so it would be really useful to be able have these stored and managed within the repository itself. Each set is limited to what the annex stores, so there is no bigger compromise I have to worry about apart from the compromise of the data that the annex itself manages.+"""]]
@@ -0,0 +1,12 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ nickname="joey"+ subject="comment 14"+ date="2013-05-24T16:45:25Z"+ content="""+I apologise for incorrect information. I was thinking about defaults when using the webapp.++I have verified that embedcreds=yes stores the AWS creds, always.+++"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="basak"+ ip="2001:8b0:1c8::2"+ subject="Recovering from a clone"+ date="2013-05-22T18:32:05Z"+ content="""+How do I recover a special remote from a clone, please? I see that `remote.log` has most of the details, but my remote is not configured on my clone and I see no obvious way to do it. And I used `embedcreds`, but the only credentials I can see are stored in .git/annex/creds/ so did not survive a clone. I'm confused because the documentation here for `embedcreds` says that clones should have access.++As a workaround, it looks like copying the remote over from `.git/config` as well as the credentials from `.git/annex/creds/` seems to work. Is there some other way I'm supposed to do this, or is this the intended way?+"""]]
@@ -0,0 +1,23 @@+[[!comment format=mdwn+ username="http://sekenre.wordpress.com/"+ nickname="sekenre"+ subject="Synchronizing Bup repositories"+ date="2013-05-07T16:46:34Z"+ content="""+Hi All,++I managed to answer my questions above about copying changes between local bup repositories efficiently.++You run the following commands ++ git annex copy . --to bup_repo_1 # Uses bup split in the background (slow)+ rsync -av /mnt/repodisk1/repo/ /mnt/repodisk2/repo/ \+ --exclude=config --exclude=*.bloom --exclude=*.midx # rsync without bup-specific indices (speed depends on delta between repositories)+ BUP_DIR=/mnt/repodisk2/repo/ bup midx -a && bup bloom # rebuild bup-specific indices on the target (this is extremely fast)+ git annex copy . --to bup_repo_2 # Records file is now available in repo2 (also extremely fast)++Now `git annex whereis` will show the correct location and `git annex get <file> --from bup_repo_2` will work.++So far in my testing I haven't found any problems...++"""]]
@@ -0,0 +1,24 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawnAvbXOnK57sqgvZvxkbG74NUKBDwKDcuk"+ nickname="Tim"+ subject="bup location data not synced through annex assistant"+ date="2013-05-15T15:08:54Z"+ content="""+I set up 2 servers running git annex assistant, both with a ~/annex dir and an additional ~/annex-bup bup repo. There is no additional cloud repository.+For test, I added my /etc dir which uploaded correctly from server1, but which never arrived on server2++ bup@bup1:~/annex/etc$ git annex whereis updatedb.conf+ whereis updatedb.conf (3 copies) + 687d3a7f-4798-4dbe-8774-1785b8ab6b7d -- here (bup@bup1:~/annex)+ adfc1307-771f-40e9-b794-bae2e1f21b8b -- bup2-annex-bup+ e4e0ac0b-992a-4312-a4ac-fc8d3d9f7c0f -- bup1-annex-bup+ ok++ bup@bup2:~/annex/etc$ git annex whereis updatedb.conf+ whereis updatedb.conf (1 copy) + 687d3a7f-4798-4dbe-8774-1785b8ab6b7d -- bup1 (bup@bup1:~/annex)+ ok++As you can see, server 2 just doesn't know the data is already on it's own disk in it's local bup repo.+Is there a reason this data does not get synced? Should I set up a transfer repo?+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawnAvbXOnK57sqgvZvxkbG74NUKBDwKDcuk"+ nickname="Tim"+ subject="my bad"+ date="2013-05-15T15:39:31Z"+ content="""+Sorry, looks like I did initremote twice on the same folder, instead of enableremote the second time...+"""]]
@@ -0,0 +1,43 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkgbXwQtPQSG8igdS7U8l031N8sqDmuyvk"+ nickname="Albert"+ subject="Error with bup and gnupg"+ date="2012-10-22T20:56:56Z"+ content="""+Hello,++I get this error when trying to use git-annex with bup and gnupg:++<pre>+move importable_pilot_surveys.tar (gpg) (checking localaseebup...) (to localaseebup...) +Traceback (most recent call last):+ File \"/usr/lib/bup/cmd/bup-split\", line 133, in <module>+ progress=prog)+ File \"/usr/lib/bup/bup/hashsplit.py\", line 167, in split_to_shalist+ for (sha,size,bits) in sl:+ File \"/usr/lib/bup/bup/hashsplit.py\", line 118, in _split_to_blobs+ for (blob, bits) in hashsplit_iter(files, keep_boundaries, progress):+ File \"/usr/lib/bup/bup/hashsplit.py\", line 86, in _hashsplit_iter+ bnew = next(fi)+ File \"/usr/lib/bup/bup/helpers.py\", line 86, in next+ return it.next()+ File \"/usr/lib/bup/bup/hashsplit.py\", line 49, in blobiter+ for filenum,f in enumerate(files):+ File \"/usr/lib/bup/cmd/bup-split\", line 128, in <genexpr>+ files = extra and (open(fn) for fn in extra) or [sys.stdin]+IOError: [Errno 2] No such file or directory: '-'+</pre>+++I was able to work-around this issue by altering /usr/lib/bup/cmd/bup-split (though I don't think its a bup bug) to just pull from stdin:++files = [sys.stdin]++on ~ line 128.++Any ideas? Also, do you think that bup's data-deduplication does anything when gnupg is enabled, i.e. is it just as well to use a directory remote with gnupg?++Thanks! Git annex rules!++Albert+"""]]
@@ -0,0 +1,12 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ ip="4.154.0.23"+ subject="comment 2"+ date="2012-10-23T20:01:43Z"+ content="""+@Albert, thanks for reporting this bug (but put them in [[bugs]] in future please).++This is specific to using the bup special remote with encryption. Without encryption it works. And no, it won't manage to deduplicate anything that's encrypted, as far as I know. ++I think bup-split must have used - for stdin in the past, but now, it just reads from stdin when no file is specified, so I've updated git-annex.+"""]]
@@ -0,0 +1,17 @@+[[!comment format=mdwn+ username="http://sekenre.wordpress.com/"+ nickname="sekenre"+ subject="Bup remotes in git-annex assistant"+ date="2013-03-13T12:54:56Z"+ content="""+Hi,++Is the bup remote available via the Assistant user interface?++Unrelated question;++If you are syncing files between two bup repos on local usb drives, does it use git to sync the changes or does it use \"bup split\" to re-add the file? (Basically, is the syncing as efficient as possible using git-annex or would I have to go to a lower level)++Many Thanks,+Sek+"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ nickname="joey"+ subject="comment 4"+ date="2013-03-13T16:05:50Z"+ content="""+I don't plan to support creating bup spefial remotes in the assistant, currently. Of course the assistant can use bup special remotes you set up.++Your two bup repos would be synced using bup-split.+"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawnZWCbRYPVnwscdkdEDwgQHZJLwW6H_AHo"+ nickname="Tobias"+ subject="bup fail?"+ date="2013-03-31T21:05:32Z"+ content="""+I've run into problems storing a huge number of files in the bup repo. It seems that thousands of branches are a problem. I don't know if it's a problem of git-annex, bup, or the filesystem.++How about adding an option to store tree/commit ids in git-annex instead of using branches in bup?+"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ nickname="joey"+ subject="comment 7"+ date="2013-04-02T21:24:06Z"+ content="""+`bup-split` uses a git branch to name the objects stored in the bup repository. So it will be limited by any scalability issues affecting large numbers of git branches. I don't know what those are.++Yes, it would be possible to make git-annex store this in the git-annex branch instead.+"""]]
@@ -0,0 +1,12 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawlsXhOlsW6RaGR83VNSMxPh159l5dFau70"+ nickname="Yung-Chin"+ subject="re scaling issue"+ date="2013-05-03T14:57:51Z"+ content="""+Tobias/joey,++I think there are at least two scaling issues that may be causing you trouble. One is that bup writes pack+idx files rather than bare objects, and if you send 1 file per call to bup-split, you end up with a pair of pack and idx files for each such call. When you later try to retrieve a blob, bup currently just calls git, and git will have to traverse all these tiny idx files looking for the right hash (bare objects you could at least find by name). You can probably ameliorate the pain by calling git repack (look at the -a and --max-pack-size switches) on your bup repository. The other is the \"thousands of branches\" issue, and I think \"git pack-refs --all\" (that's again on your bup repository) might help a little bit. ++It would certainly help performance if you could store blob/tree ids in git-annex instead of branch names. For small files, all bup would need to store is a blob, but currently you end up storing a blob, a tree, and a commit (and looking-up all of those, plus the ref too, on calling bup-join). (you might want to patch bup-split, so it would allow you to ask it for \"--blob-or-tree\", because currently if you say you pass it -b for blob-ids, then for bigger files you get a series of IDs, whereas you'd be much better off with a tree-id there)+"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawlsXhOlsW6RaGR83VNSMxPh159l5dFau70"+ nickname="Yung-Chin"+ subject="comment 9"+ date="2013-05-03T16:34:05Z"+ content="""+Thinking about this some more, a very elegant way to make a bup remote could actually be to just pass the whole .git/annex tree into bup-index/save (you could avoid sending some files by only bup-indexing select subtrees, or by using --exclude-*'s, but you'd run bup-save over the whole .git/annex tree). You could then use bup-restore to retrieve files or whole subtrees, and you'd refer to the files you're retrieving by their actual pathname under which they live in .git/annex (if that doesn't make sense it's because I've misunderstood how git-annex is organised!), so something like \"bup restore branch_name/latest/.git/annex/aa/bb/sha-of-some-sort\" would work - that's cute, right? And you'd only have 1 branch.++However... somebody who is good with lazy-evaluation would need to rework bup.vfs: currently, if you'd call bup-restore on a path like that, it would instantiate a _lot_ of vfs-nodes you don't need - to begin with, it would make a node for every commit you ever made (on any branch!) - on a big repository you'd wait ages for it to just find the commit objects...+"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="http://yarikoptic.myopenid.com/"+ nickname="site-myopenid"+ subject="How to establish local preference for (special) remotes"+ date="2013-05-22T14:06:48Z"+ content="""+Sorry if it is RTFM... If I have multiple original (reachable) remotes, how could I establish my preference for which one to be used in any given location?++usecase: if I clone a repository within amazon cloud instance -- I would now prefer if this (or all -- user-wide configuration somehow?) repository 'get's load from URLs originating in the cloud of this zone (e.g. having us-east-1.s3.amazonaws.com/ in their URLs).+"""]]
@@ -0,0 +1,12 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawmkBwMWvNKZZCge_YqobCSILPMeK6xbFw8"+ nickname="develop"+ subject="Remote costs"+ date="2013-05-22T14:15:03Z"+ content="""+This should be implemented with costs++I refer you too: http://git-annex.branchable.com/design/assistant/blog/day_213__costs/++This has been implemented in the assistant, so if you use that, changing priority should be as simple as changing the order of the remotes on the web interface. Whichever remote is highest on the list, is the one your client will fetch from.+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ nickname="joey"+ subject="comment 14"+ date="2013-05-22T14:30:00Z"+ content="""+You do not need to use the assistant to configure the costs of remotes. Just set `remote.<name>.annex-cost` to appropriate values. See also the documentation for the `remote.<name>.annex-cost-command` which allows your own code to calculate costs.+"""]]
@@ -0,0 +1,11 @@+[[!comment format=mdwn+ username="http://yarikoptic.myopenid.com/"+ nickname="site-myopenid"+ subject="remotes costs"+ date="2013-05-22T18:33:11Z"+ content="""+Thank you -- that is nice!++Could costs be presented in 'whereis' and 'status' commands? e.g. like we know APT repositories priorities from apt-cache policy -- now I do not see them (at least in 4.20130501... updating to sid's 0521 now)++"""]]
@@ -0,0 +1,12 @@+[[!comment format=mdwn+ username="http://yarikoptic.myopenid.com/"+ nickname="site-myopenid"+ subject="compression -- storage and transfer"+ date="2013-05-22T18:48:59Z"+ content="""+Is there any remote which would not only compress during transfer (I believe rsync does that, right?) but also store objects compressed?++I thought bup would do both -- but it seems that git annex receives data uncompressed from a bup remote, and bup remote requires ssh access.++In my case I want to make publicly available files which are binary blobs which could be compressed very well. It would be a pity if I waste storage on my end and also incur significant traffic, which could be avoided if data load was transferred compressed. May be HTTP compression (http://en.wikipedia.org/wiki/HTTP_compression) could somehow be used efficiently for this purpose (not sure if load then originally could already reside in a compressed form to avoid server time to re-compress it)?+"""]]
@@ -0,0 +1,12 @@+[[!comment format=mdwn+ username="http://yarikoptic.myopenid.com/"+ nickname="site-myopenid"+ subject="Re: compression -- storage and transfer"+ date="2013-05-22T19:17:33Z"+ content="""+ha -- apparently it is trivial to configure apache to serve pre-compressed files (e.g. see http://stackoverflow.com/questions/75482/how-can-i-pre-compress-files-with-mod-deflate-in-apache-2-x) and they arrive compressed to client with++Content-Encoding: gzip++but unfortunately git-annex doesn't like those (fails to \"verify\") -- do you think it could be implemented for web \"special remotes\"? that would be really nice -- then I could store such load on another website, and addurl links to the compressed content+"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ nickname="joey"+ subject="comment 18"+ date="2013-05-23T23:25:02Z"+ content="""+All special remotes store files compressed when you enable encryption. Not otherwise, though.++As far as the web special remote and pre-compressed files, files are downloaded from the web using `wget` or (of wget is not available) `curl`. So if you can make it work with those commands, it should work.+"""]]
@@ -0,0 +1,9 @@+[[!comment format=mdwn+ username="http://yarikoptic.myopenid.com/"+ nickname="site-myopenid"+ subject="compressed storage/transfer -- gzip Content-Type"+ date="2013-05-25T06:41:37Z"+ content="""+FWIW -- eh -- unfortunately it seems not that transparent. wget seems to not support decompression at all, curl can do with explicit --compressed, BUT it doesn't distinguish url to a \"natively\" .gz file and pre-compressed content. And I am not sure if it is possible to anyhow reliably distinguish the two urls. In the case of obtaining pre-compressed file from my sample apache server the only difference in the http response header is that it gets \"compound\" ETag:+compare ETag: \"3acb0e-17b38-4dd5343744660\" (for directly asking zeros100.gz) vs \"3acb0e-17b38-4dd5343744660;4dd5344e1537e\" (requesting zeros100) where portion past \";\" I guess signals the caching tag for gzipping, but not exactly sure on that since it seems to be not a part of standard. Also for zeros100 I am getting \"TCN: choice\"... once again not sure if that is any how reliably indicative for my purpose. So I guess there is no good way ATM via Content-Type request.+"""]]
@@ -50,7 +50,7 @@ into 1024 buckets. * `ANNEX_HASH_2` - another hash value, can be used for a second level of hashing -The setting to use in git config for the hook commands are as follows:+The settings to use in git config for the hook commands are as follows: * `annex.$hooktype-store-hook` - Command run to store a key in the special remote. `ANNEX_FILE` contains the content to be stored.@@ -68,3 +68,38 @@ if and only if the key has been actively verified to be present in the special remote (caching presence information is a very bad idea); all other output to stdout will be ignored.++## combined hook program++Rather than setting all of the above hooks, you can write a single+program that handles everything, and set a single hook to make it be used.++ # git config annex.demo-hook /usr/local/bin/annexdemo+ # git annex initremote mydemorepo type=hook hooktype=demo encryption=none++The program just needs to look at the `ANNEX_ACTION` environment variable+to see what it's being asked to do For example:++[[!format sh """+#!/bin/sh+set -e+case "$ANNEX_ACTION" in+ store)+ demo-upload "$ANNEX_HASH_1/$ANNEX_HASH_2/$ANNEX_KEY" < "$ANNEX_FILE"+ ;;+ retrieve)+ demo-download "$ANNEX_HASH_1/$ANNEX_HASH_2/$ANNEX_KEY" > "$ANNEX_FILE"+ ;;+ remove)+ demo-nuke "$ANNEX_HASH_1/$ANNEX_HASH_2/$ANNEX_KEY"+ ;;+ checkpresent)+ if demo-exists "$ANNEX_HASH_1/$ANNEX_HASH_2/$ANNEX_KEY"; then+ echo "$ANNEX_KEY"+ fi+ *)+ echo "unknown ANNEX_ACTION: $ANNEX_ACTION" >&2+ exit 1+ ;;+esac+"""]]
@@ -0,0 +1,32 @@+[[!comment format=mdwn+ username="helmut"+ ip="89.0.176.236"+ subject="Asynchronous hooks?"+ date="2012-10-13T09:46:14Z"+ content="""+Is there a way to use asynchronous remotes? Interaction with git annex would have to+split the part of initiating some action from completing it.++I imagine I could `git annex copy` a file to an asynchronous remote and the command+would almost immediately complete. Later I would learn that the transfer is+completed, so the hook must be able to record that information in the `git-annex`+branch. An additional plumbing command seems required here as well as a way to+indicate that even though the store-hook completed, the file is not transferred.++Similarly `git annex get` would immediately return without actually fetching the+file. This should already be possible by returning non-zero from the retrieve-hook.+Later the hook could use plumbing level commands to actually stick the received file+into the repository.++The remove-hook should need no changes, but the checkpresent-hook would be more like+a trigger without any actual result. The extension of the plumbing required for the+extension to the receive-hook could update the location log. A downside here is that+you never know when a fsck has completed.++My proposal does not include a way to track the completion of actions, but relies on+the hook to always complete them reliably. It is not clear that this is the best road+for asynchronous hooks.++One use case for this would be a remote that is only accessible via uucp. Are there+other use cases? Is the drafted interface useful?+"""]]
@@ -0,0 +1,11 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawmWg4VvDTer9f49Y3z-R0AH16P4d1ygotA"+ nickname="Tobias"+ subject="User defined server"+ date="2013-04-17T09:45:59Z"+ content="""+It would be nice if you could expand the XMPP setup in the assistant to support an \"advanced\" settings view where a custom server could be defined.++Example: I have a google Apps domain called mytest.com, with the users bla1@mytest.com and bla2@mytest.com. When trying to add either of those accounts to the assistant XMPP will try to use mytest.com as the jabber server, and not googles server.++"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawmRFKwny4rArBaz-36xTcsJYqKIgdDaw5Q"+ nickname="Andrew"+ subject="comment 2"+ date="2013-04-17T22:28:39Z"+ content="""+Yeah, I agree, this would be nice. ++For your own domain, you can configure DNS like this: [[http://support.google.com/a/bin/answer.py?hl=en&answer=34143]] to make XMPP find the right server. But for some that's not an option and the \"advanced\" mode would be useful in that case.+"""]]
@@ -11,7 +11,7 @@ [[!format sh """ # If you can, paste a complete transcript of the problem occurring here.-# If the problem is with the git-annex assistant, paste in .git/annex/debug.log+# If the problem is with the git-annex assistant, paste in .git/annex/daemon.log # End of transcript or log.
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="https://me.yahoo.com/a/2djv2EYwk43rfJIAQXjYt_vfuOU-#a11a6"+ nickname="Olivier R"+ subject="It doesn't work 100%"+ date="2012-05-03T21:42:54Z"+ content="""+When you remove tracked files... it doesn't show the new status. it's like if the file was ignored.+++"""]]
@@ -0,0 +1,28 @@+dropboxannex+=========++Hook program for gitannex to use dropbox as backend++# Requirements:++ python2++Credit for the Dropbox api interface goes to Dropbox.++# Install+Clone the git repository in your home folder.++ git clone git://github.com/TobiasTheViking/dropboxannex.git ++This should make a ~/dropboxannex folder++# Setup+Run the program once to set it up.++ cd ~/dropboxannex; python2 dropboxannex.py++# Commands for gitannex:++ git config annex.dropbox-hook '/usr/bin/python2 ~/dropboxannex/dropboxannex.py'+ git annex initremote dropbox type=hook hooktype=dropbox encryption=shared+ git annex describe dropbox "the dropbox library"
@@ -0,0 +1,49 @@+Hook program for gitannex to use flickr as backend.++This allows storing any type of file on flickr, not only images and movies.++# Requirements:++ python2++Credit for the flickr api interface goes to: <http://stuvel.eu/flickrapi> +Credit for the png library goes to: <https://github.com/drj11/pypng> +Credit for the png tEXt patch goes to: <https://code.google.com/p/pypng/issues/detail?id=65>++## Install++Clone the git repository in your home folder.++ git clone git://github.com/TobiasTheViking/flickrannex.git ++This should make a ~/flickrannex folder++## Setup++Run the program once to set it up. ++ cd ~/flickrannex; python2 flickrannex.py++After the setup has finished, it will print the git-annex configure lines.++## Configuring git-annex++ git config annex.flickr-hook '/usr/bin/python2 ~/flickrannex/flickrannex.py'+ git annex initremote flickr type=hook hooktype=flickr encryption=shared+ git annex describe flickr "the flickr library"++## Notes++### Unencrypted mode++The photo name on flickr is currently the [[key|backends]] used by git-annex.++### Encrypted mode++The current version base64 encodes all the data, which results in ~35%+larger filesize.++I might look into yyenc instead. I'm not sure if it will work in the tEXt+field.++-- Tobias
@@ -0,0 +1,28 @@+googledriveannex+=========++Hook program for gitannex to use Google Drive as backend++# Requirements:++ python2++Credit for the googledrive api interface goes to google++## Install+Clone the git repository in your home folder.++ git clone git://github.com/TobiasTheViking/googledriveannex.git ++This should make a ~/googledriveannex folder++## Setup+Run the program once to make an empty config file++ cd ~/googledriveannex; python2 googledriveannex.py++## Commands for gitannex:++ git config annex.googledrive-hook '/usr/bin/python2 ~/googledriveannex/googledriveannex.py'+ git annex initremote googledrive type=hook hooktype=googledrive encryption=shared+ git annex describe googledrive "the googledrive library"
@@ -3,6 +3,7 @@ # Requirements: + python2 requests>=0.10 pycrypto @@ -23,16 +24,11 @@ cd ~/megaannex; python2 megaannex.py -Edit the megaannex.conf file. Add your mega.co.nz username and password--Note: The folder option in the megaannex.conf file isn't yet used. +Edit the megaannex.conf file. Add your mega.co.nz username, password, and folder name. ## Configuring git-annex - git config annex.mega-store-hook 'python2 ~/megaannex/megaannex.py store --subject $ANNEX_KEY --file $ANNEX_FILE'- git config annex.mega-retrieve-hook 'python2 ~/megaannex/megaannex.py getfile --subject $ANNEX_KEY --file $ANNEX_FILE'- git config annex.mega-checkpresent-hook 'python2 ~/megaannex/megaannex.py fileexists --subject $ANNEX_KEY'- git config annex.mega-remove-hook 'python2 ~/megaannex/megaannex.py delete --subject $ANNEX_KEY'+ git config annex.mega-hook '/usr/bin/python2 ~/megaannex/megaannex.py' git annex initremote mega type=hook hooktype=mega encryption=shared git annex describe mega "the mega.co.nz library"
@@ -0,0 +1,28 @@+owncloudannex+=========++Hook program for gitannex to use owncloud as backend++# Requirements:++ python2++Credit for the Owncloud api interface goes to me.++# Install+Clone the git repository in your home folder.++ git clone git://github.com/TobiasTheViking/owncloudannex.git ++This should make a ~/owncloudannex folder++# Setup+Run the program once to set it up.++ cd ~/owncloudannex; python2 owncloudannex.py++# Commands for gitannex:++ git config annex.owncloud-hook '/usr/bin/python2 ~/owncloudannex/owncloudannex.py'+ git annex initremote owncloud type=hook hooktype=owncloud encryption=shared+ git annex describe owncloud "the owncloud library"
@@ -0,0 +1,29 @@+skydriveannex+=========++Hook program for gitannex to use [skydrive](http://en.wikipedia.org/wiki/SkyDrive) (previously *Windows Live SkyDrive* and *Windows Live Folders*) as backend++# Requirements:++ python2+ python-yaml++Credit for the Skydrive api interface goes to https://github.com/mk-fg/python-skydrive++# Install+Clone the git repository in your home folder.++ git clone git://github.com/TobiasTheViking/skydriveannex.git ++This should make a ~/skydriveannex folder++# Setup+Run the program once to set it up.++ cd ~/skydriveannex; python2 skydriveannex.py++# Commands for gitannex:++ git config annex.skydrive-hook '/usr/bin/python2 ~/skydriveannex/skydriveannex.py'+ git annex initremote skydrive type=hook hooktype=skydrive encryption=shared+ git annex describe skydrive "the skydrive library"
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawnoUOqs_lbuWyZBqyU6unHgUduJwDDgiKY"+ nickname="Matt"+ subject="ANNEX_S3 vs AWS for keys"+ date="2012-05-29T12:24:25Z"+ content="""+The instructions state ANNEX_S3_ACCESS_KEY_ID and ANNEX_SECRET_ACCESS_KEY but git-annex cannot connect with those constants. git-annex tells me to set both \"AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY\" instead, which works. This is with Xubuntu 12.04.+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://joeyh.name/"+ ip="4.153.81.112"+ subject="comment 2"+ date="2012-05-29T19:10:42Z"+ content="""+Thanks, I've fixed that. (You could have too.. this is a wiki ;)+"""]]
@@ -0,0 +1,1 @@+It would be wonderful if a pre-built package would be available for Synology NAS. Basically, this is an ARM-based Linux. It has most of the required shell commands either out of the box or easily available (through ipkg). But I think it would be difficult to install the Haskell compiler and all the required modules, so it would probably be better to cross-compile targeting ARM.
@@ -0,0 +1,7 @@+There are times when it is handy to be able to upload a file to a web host somewhere and share a link for that file to a select few people.++It seems to be that the assistant could handle this scenario. It could generate a directory with a random name on the remote, and transfer the file there (using the existing filename) and the appropriate URL could be displayed in the assistant webapp to allow the user to copy the URL to send it to the appropriate people.++Note: Joey and I had a quick chat about this use case at LCA2013.++[[!tag design/assistant]]
@@ -0,0 +1,11 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawl9sYlePmv1xK-VvjBdN-5doOa_Xw-jH4U"+ nickname="Richard"+ subject="comment 1"+ date="2011-05-17T07:27:02Z"+ content="""+Sounds like a good idea.++* git annex fsck (or similar) should check/rebuild the caches+* I would simply require a clean tree with a verbose error. 80/20 rule and defaulting to save actions.+"""]]
@@ -0,0 +1,25 @@+It would be good to have something in between the hook special remote and+the built-in special remotes. The hook is easy to set up, but its simple+interface misses some features that a more full-features interface could+provide to a third-party program that wants to provide the best possible+special remote it can w/o being written in haskell:++* No way to send progress updates when uploading, so no progress bars for uploads from hook special remotes in the webapp.+* No way to verify the `initremote` parameters include all needed configuration, and do any initalization needed.+* No way to query and/or set the remote.log while it's running. (Well, technically, `git annex enableremote` can set values..)+* No way to store per-key information to the git-annex branch.+* No (easy) way to split files into chunks.++Some of these features could be added to git-annex as subcommands. Which would+improve the general programmability and flexability of git-annex. OTOH,+running `git-annex upload-progress` repeatedly is pretty ugly. Or the+interface could provide a channel for the program and git-annex to+communicate back and forth on. Maybe a mix of the two?++A final feature such an interface should provide is the ability to drop a+program into PATH and have it just work, without the user needing to do any+configuration beyond `initremote`. So, `git annex initremote foo type=$bar`+should look for `git-annex-remote-$bar` in PATH if that's not a built-in+special remote name.++--[[Joey]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawln3ckqKx0x_xDZMYwa9Q1bn4I06oWjkog"+ nickname="Michael"+ subject="comment 1"+ date="2013-03-01T01:26:36Z"+ content="""+This would indeed be very helpful when remotely mounting a photo/video collection over samba.+"""]]
@@ -0,0 +1,9 @@+[[!comment format=mdwn+ username="http://edheil.wordpress.com/"+ ip="173.162.44.162"+ subject="comment 2"+ date="2013-03-01T04:50:28Z"+ content="""++1 this would be sweet as hell++"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawkRITTYYsN0TFKN7G5sZ6BWGZOTQ88Pz4s"+ nickname="Zoltán"+ subject="cygwin"+ date="2012-05-15T00:14:08Z"+ content="""+What about [Cygwin](http://cygwin.com/)? It emulates POSIX fairly well under Windows (including signals, forking, fs (also things like /dev/null, /proc), unix file permissions), has all standard gnu utilities. It also emulates symlinks, but they are unfortunately incompatible with NTFS symlinks introduced in Vista [due to some stupid restrictions on Windows](http://cygwin.com/ml/cygwin/2009-10/msg00756.html).++If git-annex could be modified to not require symlinks to work, the it would be a pretty neat solution (and you get a real shell, not some command.com on drugs (aka cmd.exe))+"""]]
@@ -0,0 +1,12 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawk5cj-itfFHq_yhJHdzk3QOPp-PNW_MjPU"+ nickname="Michael"+ subject="+1 Cygwin"+ date="2012-05-23T19:30:21Z"+ content="""+Windows support is a must. In my experience, binary file means proprietary editor, which means Windows.++Unfortunately, there's not much overlap between people who use graphical editors in Windows all day vs. people who are willing to tolerate Cygwin's setup.exe, compile a Haskell program, learn git and git-annex's 90-odd subcommands, and use a mintty terminal to manage their repository, especially now that there's a sexy GitHub app for Windows.++That aside, I think Windows-based content producers are still *the* audience for git-annex. First Windows support, then a GUI, then the world.+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="http://xolus.net/openid/max"+ nickname="B0FH"+ subject="What about NTFS support ?"+ date="2012-08-02T17:45:10Z"+ content="""+Has git-annex been tested with an NTFS-formatted disk under Linux ? NTFS is supposed to be case-sensitive and to allow symlinks, and these are supposed to work with ntfs3g.+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawlc1og3PqIGudOMkFNrCCNg66vB7s-jLpc"+ nickname="Paul"+ subject="Re: What about NTFS support?"+ date="2012-08-16T19:30:38Z"+ content="""+I successfully use git-annex on an NTFS formatted external USB drive, so yes, it is possible and works well.+"""]]
@@ -0,0 +1,10 @@+[[!comment format=mdwn+ username="https://me.yahoo.com/a/dASECLNzvckz4VwqUGYsvthiplY.#d2c27"+ nickname="A. D. Sicks"+ subject="comment 5"+ date="2012-09-09T23:48:21Z"+ content="""+Haskell has C++ binding, so it should be possible to port it to .net/Mono with a VB GUI for Windows users. Windows has a primitive form of symlinks called shortcuts. Perhaps shortcut support in Windows could replace the use of symlinks. I've used shortcuts since XP to put my home Windows directory on another partition and never had a hitch...++If anyone is interested in working on this, hit me up. I would like to use this in my XP vbox to have access to files on my host OS...I have a student edition of Visual Studio 2005 to do an open source port...+"""]]
@@ -0,0 +1,8 @@+[[!comment format=mdwn+ username="https://www.google.com/accounts/o8/id?id=AItOawnlwEMhiNYv__mEUABW4scn83yMraC3hqE"+ nickname="Sean"+ subject="NTFS symlinks"+ date="2013-01-11T21:44:21Z"+ content="""+It seems that NTFS (from Vista forward) has full POSIX support for symlinks. At least, Wikipedia [seems to think so.](http://en.wikipedia.org/wiki/NTFS_symbolic_link). What about doing like GitHub and using MinGW for compatibility? Cygwin absolutely blows in terms of installation size and compatability with the rest of Windows.+"""]]
@@ -3,3 +3,5 @@ Currently XMPP fails if you use a google apps account. Since the domain provided in the email is not the same as the XMPP server. Same goes for webdav support. If i have my own webdav server somewhere on the internet there is no way to set it up in the assistant.++[[!tag /design/assistant]]
@@ -0,0 +1,7 @@+I would like to use the automated AWS lifecycle rules to move the git annex files store on S3 to Glacier after a bit of time. Git annex need must support this kind of S3 files explicitly in order for it to work.++This is different from the adding a Glacier remote to git annex because of the reasons explained in <http://aws.typepad.com/aws/2012/11/archive-s3-to-glacier.html>.++Basically, the files moved by AWS from S3 to Glacier are not available under the normal Glacier API. In fact, the moved S3 files are listed as available but under the `GLACIER` storage class and need a RESTORE request before they can be GET like other S3 files. Trying to GET an S3 file that has been moved to Glacier will not restore it from Glacier and will result in an 403 error.++I suppose DELETE needs special care as well.
@@ -0,0 +1,17 @@+I am running centralized git-annex exclusively.++Similar to++ git annex get++I'd like to have a++ git annex put++which would put all files on the default remote(s).++My main reason for not wanting to use copy --to is that I need to specify the remote's name in this case which makes writing a wrapper unnecessarily hard. Also, this would allow++ mr push++to do the right thing all by itself.
@@ -0,0 +1,16 @@+git annex vicfg should display valid repository group names++For trust levels the possible values are displayed:++ # Repository trust configuration+ # (Valid trust levels: trusted semitrusted untrusted dead)+ ...++The same is not currently done for repository groups+ + # Repository groups+ # (Separate group names with spaces)++Thanks.++> [[done]] --[[Joey]]
@@ -225,6 +225,11 @@ (or encryption=emailaddress) to specify a gpg key that can access the encrypted special remote. .IP+Note that with encryption enabled, a gpg key is created. This requires+sufficient entropy. If initremote seems to hang or take a long time+while generating the key, you may want to ctrl\-c it and re\-run with \-\-fast,+which causes it to use a lower\-quality source of randomness.+.IP Example Amazon S3 remote: .IP git annex initremote mys3 type=S3 encryption=me@example.com datacenter=EU@@ -271,6 +276,13 @@ .IP .IP "ungroup repository groupname" Removes a repository from a group.+.IP+.IP "content repository [expression]"+When run with an expression, configures the content that is preferred+to be held in the archive. See PREFERRED CONTENT below.+.IP+Without an expression, displays the current preferred content setting+of the repository. .IP .IP "vicfg" Opens EDITOR on a temp file containing most of the above configuration
@@ -1,5 +1,5 @@ Name: git-annex-Version: 4.20130521.2+Version: 4.20130601 Cabal-Version: >= 1.8 License: GPL Maintainer: Joey Hess <joey@kitenet.net>
@@ -11,7 +11,7 @@ export ANDROID_SDK_ROOT?=$(HOME)/tmp/adt-bundle-linux-x86/sdk export ANDROID_NDK_ROOT?=$(HOME)/tmp/android-ndk-r8d -# Where to store the $(GIT_ANNEX_ANDROID_SOURCETREE)s to utilities. This+# Where to store the source tree used to build utilities. This # directory will be created by `make source`. GIT_ANNEX_ANDROID_SOURCETREE?=$(HOME)/tmp/android-sourcetree @@ -64,7 +64,7 @@ $(GITTREE)/libexec/git-core/git-web--browse # Most of git is in one multicall binary, but a few important # commands are still shell scripts. Those are put into- # a tarball, along with a list of all the hard links that should be+ # a tarball, along with a list of all the links that should be # set up. cd $(GITTREE) && mkdir -p links cd $(GITTREE) && find -samefile bin/git -not -wholename ./bin/git > links/git
@@ -0,0 +1,25 @@+From df0f41f92d003f7d59ef927737ffec3a9bd61827 Mon Sep 17 00:00:00 2001+From: Joey Hess <joey@kitenet.net>+Date: Tue, 7 May 2013 18:41:01 -0400+Subject: [PATCH] avoid cabal hell++---+ gsasl.cabal | 2 +-+ 1 file changed, 1 insertion(+), 1 deletion(-)++diff --git a/gsasl.cabal b/gsasl.cabal+index d991873..c5c2b19 100644+--- a/gsasl.cabal++++ b/gsasl.cabal+@@ -31,7 +31,7 @@ library+ build-depends:+ base >= 4.0 && < 5.0+ , transformers >= 0.2+- , bytestring >= 0.9++ , bytestring >= 0.10.3.0+ + pkgconfig-depends: libgsasl >= 1.1+ +-- +1.7.10.4+
@@ -0,0 +1,71 @@+From 8fddef803ee9191ca15363283b7e4d5af4c70f3a Mon Sep 17 00:00:00 2001+From: Joey Hess <joey@kitenet.net>+Date: Thu, 28 Feb 2013 23:34:10 -0400+Subject: [PATCH] disable TH++---+ Database/Persist/GenericSql/Internal.hs | 6 +-----+ Database/Persist/GenericSql/Raw.hs | 5 ++---+ 2 files changed, 3 insertions(+), 8 deletions(-)++diff --git a/Database/Persist/GenericSql/Internal.hs b/Database/Persist/GenericSql/Internal.hs+index f109887..5273398 100644+--- a/Database/Persist/GenericSql/Internal.hs++++ b/Database/Persist/GenericSql/Internal.hs+@@ -14,7 +14,6 @@ module Database.Persist.GenericSql.Internal+ , createSqlPool+ , mkColumns+ , Column (..)+- , logSQL+ , InsertSqlResult (..)+ ) where+ +@@ -33,7 +32,7 @@ import Data.Monoid (Monoid, mappend, mconcat)+ import Database.Persist.EntityDef+ import qualified Data.Conduit as C+ import Language.Haskell.TH.Syntax (Q, Exp)+-import Control.Monad.Logger (logDebugS)+++ import Data.Maybe (mapMaybe, listToMaybe)+ import Data.Int (Int64)+ +@@ -197,6 +196,3 @@ tableColumn t s = go $ entityColumns t+ | x == s = ColumnDef x y z+ | otherwise = go rest+ -}+-+-logSQL :: Q Exp+-logSQL = [|\sql_foo params_foo -> $logDebugS (T.pack "SQL") $ T.pack $ show (sql_foo :: Text) ++ " " ++ show (params_foo :: [PersistValue])|]+diff --git a/Database/Persist/GenericSql/Raw.hs b/Database/Persist/GenericSql/Raw.hs+index e4bf9f4..3da8fa0 100644+--- a/Database/Persist/GenericSql/Raw.hs++++ b/Database/Persist/GenericSql/Raw.hs+@@ -26,7 +26,6 @@ import Database.Persist.GenericSql.Internal hiding (execute, withStmt)+ import Database.Persist.Store (PersistValue)+ import Data.IORef+ import Control.Monad.IO.Class+-import Control.Monad.Logger (logDebugS)+ import Control.Monad.Trans.Reader+ import qualified Data.Map as Map+ import Control.Applicative (Applicative)+@@ -134,7 +133,7 @@ withStmt :: (MonadSqlPersist m, MonadResource m)+ -> [PersistValue]+ -> Source m [PersistValue]+ withStmt sql vals = do+- lift $ $logDebugS (pack "SQL") $ pack $ show sql ++ " " ++ show vals++ -- lift $ pack $ show sql ++ " " ++ show vals+ conn <- lift askSqlConn+ bracketP+ (getStmt' conn sql)+@@ -146,7 +145,7 @@ execute x y = liftM (const ()) $ executeCount x y+ + executeCount :: MonadSqlPersist m => Text -> [PersistValue] -> m Int64+ executeCount sql vals = do+- $logDebugS (pack "SQL") $ pack $ show sql ++ " " ++ show vals++ -- pack $ show sql ++ " " ++ show vals+ stmt <- getStmt sql+ res <- liftIO $ I.execute stmt vals+ liftIO $ reset stmt+-- +1.7.10.4+
@@ -0,0 +1,308 @@+From 332c71b3f6bc4786b914e675020a23c492beee5a Mon Sep 17 00:00:00 2001+From: Joey Hess <joey@kitenet.net>+Date: Tue, 7 May 2013 19:28:06 -0400+Subject: [PATCH] remove TH++---+ Text/Coffee.hs | 54 -------------------------------------------------+ Text/Julius.hs | 56 ++++-----------------------------------------------+ Text/Roy.hs | 54 -------------------------------------------------+ Text/TypeScript.hs | 57 +---------------------------------------------------+ 4 files changed, 5 insertions(+), 216 deletions(-)++diff --git a/Text/Coffee.hs b/Text/Coffee.hs+index 2481936..3f7f9c3 100644+--- a/Text/Coffee.hs++++ b/Text/Coffee.hs+@@ -51,14 +51,6 @@ module Text.Coffee+ -- ** Template-Reading Functions+ -- | These QuasiQuoter and Template Haskell methods return values of+ -- type @'JavascriptUrl' url@. See the Yesod book for details.+- coffee+- , coffeeFile+- , coffeeFileReload+- , coffeeFileDebug+-+-#ifdef TEST_EXPORT+- , coffeeSettings+-#endif+ ) where+ + import Language.Haskell.TH.Quote (QuasiQuoter (..))+@@ -66,49 +58,3 @@ import Language.Haskell.TH.Syntax+ import Text.Shakespeare+ import Text.Julius+ +-coffeeSettings :: Q ShakespeareSettings+-coffeeSettings = do+- jsettings <- javascriptSettings+- return $ jsettings { varChar = '%'+- , preConversion = Just PreConvert {+- preConvert = ReadProcess "coffee" ["-spb"]+- , preEscapeIgnoreBalanced = "'\"`" -- don't insert backtacks for variable already inside strings or backticks.+- , preEscapeIgnoreLine = "#" -- ignore commented lines+- , wrapInsertion = Just WrapInsertion { +- wrapInsertionIndent = Just " "+- , wrapInsertionStartBegin = "(("+- , wrapInsertionSeparator = ", "+- , wrapInsertionStartClose = ") =>"+- , wrapInsertionEnd = ")"+- , wrapInsertionApplyBegin = "("+- , wrapInsertionApplyClose = ")\n"+- }+- }+- }+-+--- | Read inline, quasiquoted CoffeeScript.+-coffee :: QuasiQuoter+-coffee = QuasiQuoter { quoteExp = \s -> do+- rs <- coffeeSettings+- quoteExp (shakespeare rs) s+- }+-+--- | Read in a CoffeeScript template file. This function reads the file once, at+--- compile time.+-coffeeFile :: FilePath -> Q Exp+-coffeeFile fp = do+- rs <- coffeeSettings+- shakespeareFile rs fp+-+--- | Read in a CoffeeScript template file. This impure function uses+--- unsafePerformIO to re-read the file on every call, allowing for rapid+--- iteration.+-coffeeFileReload :: FilePath -> Q Exp+-coffeeFileReload fp = do+- rs <- coffeeSettings+- shakespeareFileReload rs fp+-+--- | Deprecated synonym for 'coffeeFileReload'+-coffeeFileDebug :: FilePath -> Q Exp+-coffeeFileDebug = coffeeFileReload+-{-# DEPRECATED coffeeFileDebug "Please use coffeeFileReload instead." #-}+diff --git a/Text/Julius.hs b/Text/Julius.hs+index 230eac3..1a0376f 100644+--- a/Text/Julius.hs++++ b/Text/Julius.hs+@@ -14,17 +14,8 @@ module Text.Julius+ -- ** Template-Reading Functions+ -- | These QuasiQuoter and Template Haskell methods return values of+ -- type @'JavascriptUrl' url@. See the Yesod book for details.+- js+- , julius+- , juliusFile+- , jsFile+- , juliusFileDebug+- , jsFileDebug+- , juliusFileReload+- , jsFileReload+-+ -- * Datatypes+- , JavascriptUrl++ JavascriptUrl+ , Javascript (..)+ , RawJavascript (..)+ +@@ -37,9 +28,11 @@ module Text.Julius+ , renderJavascriptUrl+ + -- ** internal, used by 'Text.Coffee'+- , javascriptSettings+ -- ** internal+ , juliusUsedIdentifiers++++ -- used by TH splices++ , asJavascriptUrl+ ) where+ + import Language.Haskell.TH.Quote (QuasiQuoter (..))+@@ -101,47 +94,6 @@ instance RawJS TL.Text where rawJS = RawJavascript . fromLazyText+ instance RawJS Builder where rawJS = RawJavascript+ instance RawJS Bool where rawJS = RawJavascript . toJavascript+ +-javascriptSettings :: Q ShakespeareSettings+-javascriptSettings = do+- toJExp <- [|toJavascript|]+- wrapExp <- [|Javascript|]+- unWrapExp <- [|unJavascript|]+- asJavascriptUrl' <- [|asJavascriptUrl|]+- return $ defaultShakespeareSettings { toBuilder = toJExp+- , wrap = wrapExp+- , unwrap = unWrapExp+- , modifyFinalValue = Just asJavascriptUrl'+- }+-+-js, julius :: QuasiQuoter+-js = QuasiQuoter { quoteExp = \s -> do+- rs <- javascriptSettings+- quoteExp (shakespeare rs) s+- }+-+-julius = js+-+-jsFile, juliusFile :: FilePath -> Q Exp+-jsFile fp = do+- rs <- javascriptSettings+- shakespeareFile rs fp+-+-juliusFile = jsFile+-+-+-jsFileReload, juliusFileReload :: FilePath -> Q Exp+-jsFileReload fp = do+- rs <- javascriptSettings+- shakespeareFileReload rs fp+-+-juliusFileReload = jsFileReload+-+-jsFileDebug, juliusFileDebug :: FilePath -> Q Exp+-juliusFileDebug = jsFileReload+-{-# DEPRECATED juliusFileDebug "Please use juliusFileReload instead." #-}+-jsFileDebug = jsFileReload+-{-# DEPRECATED jsFileDebug "Please use jsFileReload instead." #-}+-+ -- | Determine which identifiers are used by the given template, useful for+ -- creating systems like yesod devel.+ juliusUsedIdentifiers :: String -> [(Deref, VarType)]+diff --git a/Text/Roy.hs b/Text/Roy.hs+index cf09cec..870c9f6 100644+--- a/Text/Roy.hs++++ b/Text/Roy.hs+@@ -23,13 +23,6 @@ module Text.Roy+ -- ** Template-Reading Functions+ -- | These QuasiQuoter and Template Haskell methods return values of+ -- type @'JavascriptUrl' url@. See the Yesod book for details.+- roy+- , royFile+- , royFileReload+-+-#ifdef TEST_EXPORT+- , roySettings+-#endif+ ) where+ + import Language.Haskell.TH.Quote (QuasiQuoter (..))+@@ -37,50 +30,3 @@ import Language.Haskell.TH.Syntax+ import Text.Shakespeare+ import Text.Julius+ +--- | The Roy language compiles down to Javascript.+--- We do this compilation once at compile time to avoid needing to do it during the request.+--- We call this a preConversion because other shakespeare modules like Lucius use Haskell to compile during the request instead rather than a system call.+-roySettings :: Q ShakespeareSettings+-roySettings = do+- jsettings <- javascriptSettings+- return $ jsettings { varChar = '#'+- , preConversion = Just PreConvert {+- preConvert = ReadProcess "roy" ["--stdio"]+- , preEscapeIgnoreBalanced = "'\""+- , preEscapeIgnoreLine = "//"+- , wrapInsertion = Nothing+- {-+- Just WrapInsertion { +- wrapInsertionIndent = Just " "+- , wrapInsertionStartBegin = "(\\"+- , wrapInsertionSeparator = " "+- , wrapInsertionStartClose = " ->\n"+- , wrapInsertionEnd = ")"+- , wrapInsertionApplyBegin = " "+- , wrapInsertionApplyClose = ")\n"+- }+- -}+- }+- }+-+--- | Read inline, quasiquoted Roy.+-roy :: QuasiQuoter+-roy = QuasiQuoter { quoteExp = \s -> do+- rs <- roySettings+- quoteExp (shakespeare rs) s+- }+-+--- | Read in a Roy template file. This function reads the file once, at+--- compile time.+-royFile :: FilePath -> Q Exp+-royFile fp = do+- rs <- roySettings+- shakespeareFile rs fp+-+--- | Read in a Roy template file. This impure function uses+--- unsafePerformIO to re-read the file on every call, allowing for rapid+--- iteration.+-royFileReload :: FilePath -> Q Exp+-royFileReload fp = do+- rs <- roySettings+- shakespeareFileReload rs fp+diff --git a/Text/TypeScript.hs b/Text/TypeScript.hs+index 34bf4bf..30c5388 100644+--- a/Text/TypeScript.hs++++ b/Text/TypeScript.hs+@@ -53,65 +53,10 @@+ --+ -- 2. TypeScript: <http://typescript.codeplex.com/>+ module Text.TypeScript+- ( -- * Functions+- -- ** Template-Reading Functions+- -- | These QuasiQuoter and Template Haskell methods return values of+- -- type @'JavascriptUrl' url@. See the Yesod book for details.+- tsc+- , typeScriptFile+- , typeScriptFileReload+-+-#ifdef TEST_EXPORT+- , typeScriptSettings+-#endif++ (+ ) where+ + import Language.Haskell.TH.Quote (QuasiQuoter (..))+ import Language.Haskell.TH.Syntax+ import Text.Shakespeare+ import Text.Julius+-+--- | The TypeScript language compiles down to Javascript.+--- We do this compilation once at compile time to avoid needing to do it during the request.+--- We call this a preConversion because other shakespeare modules like Lucius use Haskell to compile during the request instead rather than a system call.+-typeScriptSettings :: Q ShakespeareSettings+-typeScriptSettings = do+- jsettings <- javascriptSettings+- return $ jsettings { varChar = '#'+- , preConversion = Just PreConvert {+- preConvert = ReadProcess "sh" ["-c", "TMP_IN=$(mktemp XXXXXXXXXX.ts); TMP_OUT=$(mktemp XXXXXXXXXX.js); cat /dev/stdin > ${TMP_IN} && tsc --out ${TMP_OUT} ${TMP_IN} && cat ${TMP_OUT}; rm ${TMP_IN} && rm ${TMP_OUT}"]+- , preEscapeIgnoreBalanced = "'\""+- , preEscapeIgnoreLine = "//"+- , wrapInsertion = Just WrapInsertion { +- wrapInsertionIndent = Nothing+- , wrapInsertionStartBegin = ";(function("+- , wrapInsertionSeparator = ", "+- , wrapInsertionStartClose = "){"+- , wrapInsertionEnd = "})"+- , wrapInsertionApplyBegin = "("+- , wrapInsertionApplyClose = ");\n"+- }+- }+- }+-+--- | Read inline, quasiquoted TypeScript+-tsc :: QuasiQuoter+-tsc = QuasiQuoter { quoteExp = \s -> do+- rs <- typeScriptSettings+- quoteExp (shakespeare rs) s+- }+-+--- | Read in a Roy template file. This function reads the file once, at+--- compile time.+-typeScriptFile :: FilePath -> Q Exp+-typeScriptFile fp = do+- rs <- typeScriptSettings+- shakespeareFile rs fp+-+--- | Read in a Roy template file. This impure function uses+--- unsafePerformIO to re-read the file on every call, allowing for rapid+--- iteration.+-typeScriptFileReload :: FilePath -> Q Exp+-typeScriptFileReload fp = do+- rs <- typeScriptSettings+- shakespeareFileReload rs fp+-- +1.7.10.4+
@@ -0,0 +1,107 @@+From abab0f8202998a3e88c5dc5f67a8245da6c174b3 Mon Sep 17 00:00:00 2001+From: Joey Hess <joey@kitenet.net>+Date: Thu, 28 Feb 2013 23:36:20 -0400+Subject: [PATCH] remove IPv6 stuff++---+ Network/Socks5.hs | 1 -+ Network/Socks5/Command.hs | 16 ++--------------+ Network/Socks5/Types.hs | 3 +--+ Network/Socks5/Wire.hs | 2 --+ 4 files changed, 3 insertions(+), 19 deletions(-)++diff --git a/Network/Socks5.hs b/Network/Socks5.hs+index 67b0060..80efb9c 100644+--- a/Network/Socks5.hs++++ b/Network/Socks5.hs+@@ -54,7 +54,6 @@ socksConnectAddr :: Socket -> SockAddr -> SockAddr -> IO ()+ socksConnectAddr sock sockserver destaddr = withSocks sock sockserver $ do+ case destaddr of+ SockAddrInet p h -> socks5ConnectIPV4 sock h p >> return ()+- SockAddrInet6 p _ h _ -> socks5ConnectIPV6 sock h p >> return ()+ _ -> error "unsupported unix sockaddr type"+ + -- | connect a new socket to the socks server, and connect the stream to a FQDN+diff --git a/Network/Socks5/Command.hs b/Network/Socks5/Command.hs+index 2952706..db994c9 100644+--- a/Network/Socks5/Command.hs++++ b/Network/Socks5/Command.hs+@@ -9,9 +9,8 @@+ --+ module Network.Socks5.Command+ ( socks5Establish+- , socks5ConnectIPV4+- , socks5ConnectIPV6+ , socks5ConnectDomainName++ , socks5ConnectIPV4 + -- * lowlevel interface+ , socks5Rpc+ ) where+@@ -23,7 +22,7 @@ import qualified Data.ByteString as B+ import qualified Data.ByteString.Char8 as BC+ import Data.Serialize+ +-import Network.Socket (Socket, PortNumber, HostAddress, HostAddress6)++import Network.Socket (Socket, PortNumber, HostAddress)+ import Network.Socket.ByteString+ + import Network.Socks5.Types+@@ -46,17 +45,6 @@ socks5ConnectIPV4 socket hostaddr port = onReply <$> socks5Rpc socket request+ onReply (SocksAddrIPV4 h, p) = (h, p)+ onReply _ = error "ipv4 requested, got something different"+ +-socks5ConnectIPV6 :: Socket -> HostAddress6 -> PortNumber -> IO (HostAddress6, PortNumber)+-socks5ConnectIPV6 socket hostaddr6 port = onReply <$> socks5Rpc socket request+- where+- request = SocksRequest+- { requestCommand = SocksCommandConnect+- , requestDstAddr = SocksAddrIPV6 hostaddr6+- , requestDstPort = fromIntegral port+- }+- onReply (SocksAddrIPV6 h, p) = (h, p)+- onReply _ = error "ipv6 requested, got something different"+-+ -- TODO: FQDN should only be ascii, maybe putting a "fqdn" data type+ -- in front to make sure and make the BC.pack safe.+ socks5ConnectDomainName :: Socket -> String -> PortNumber -> IO (SocksAddr, PortNumber)+diff --git a/Network/Socks5/Types.hs b/Network/Socks5/Types.hs+index 5dc7d5e..12dea99 100644+--- a/Network/Socks5/Types.hs++++ b/Network/Socks5/Types.hs+@@ -17,7 +17,7 @@ module Network.Socks5.Types+ import Data.ByteString (ByteString)+ import Data.Word+ import Data.Data+-import Network.Socket (HostAddress, HostAddress6)++import Network.Socket (HostAddress)+ import Control.Exception+ + data SocksCommand =+@@ -38,7 +38,6 @@ data SocksMethod =+ data SocksAddr =+ SocksAddrIPV4 HostAddress+ | SocksAddrDomainName ByteString+- | SocksAddrIPV6 HostAddress6+ deriving (Show,Eq)+ + data SocksReply =+diff --git a/Network/Socks5/Wire.hs b/Network/Socks5/Wire.hs+index 2cfed52..d3bd9c5 100644+--- a/Network/Socks5/Wire.hs++++ b/Network/Socks5/Wire.hs+@@ -41,12 +41,10 @@ data SocksResponse = SocksResponse+ + getAddr 1 = SocksAddrIPV4 <$> getWord32be+ getAddr 3 = SocksAddrDomainName <$> (getWord8 >>= getByteString . fromIntegral)+-getAddr 4 = SocksAddrIPV6 <$> (liftM4 (,,,) getWord32le getWord32le getWord32le getWord32le)+ getAddr n = error ("cannot get unknown socket address type: " ++ show n)+ + putAddr (SocksAddrIPV4 h) = putWord8 1 >> putWord32host h+ putAddr (SocksAddrDomainName b) = putWord8 3 >> putWord8 (fromIntegral $ B.length b) >> putByteString b+-putAddr (SocksAddrIPV6 (a,b,c,d)) = putWord8 4 >> mapM_ putWord32host [a,b,c,d]+ + getSocksRequest 5 = do+ cmd <- toEnum . fromIntegral <$> getWord8+-- +1.7.10.4+
binary file changed (absent → 1071 bytes)
binary file changed (absent → 587 bytes)
binary file changed (absent → 712 bytes)
@@ -27,7 +27,7 @@ if $cmd test -e "$base/bin/$prog"; then $cmd rm -f "$base/bin/$prog" fi- $cmd ln "$base/lib/lib.$prog.so" "$base/bin/$prog"+ $cmd ln -s "$base/lib/lib.$prog.so" "$base/bin/$prog" done $cmd --install $base/bin@@ -41,7 +41,7 @@ if $cmd test -e "$base/$link"; then $cmd rm -f "$base/$link" fi- $cmd ln "$base/bin/$prog" "$base/$link"+ $cmd ln -s "$base/bin/$prog" "$base/$link" done $cmd rm -f "$base/links/$prog" done@@ -116,12 +116,17 @@ fi } -if ! prep; then- $cmd echo "prep failed. Please report a bug."- read line-fi-if ! install; then- $cmd echo "install failed. Please report a bug."- read line+if $cmd test -n "$MKFIFO"; then+ # because java is insane+ $cmd mkfifo "$MKFIFO"+else+ if ! prep; then+ $cmd echo "prep failed. Please report a bug."+ read line+ fi+ if ! install; then+ $cmd echo "install failed. Please report a bug."+ read line+ fi+ run fi-run
@@ -47,11 +47,15 @@ } } - /* If this is the first run, set up busybox link. */+ /* If this is the first run, set up busybox symlink,+ * which allows busybox to run. */ if (stat("busybox", &st_buf) != 0) {- if (link("lib/lib.busybox.so", "busybox") != 0) {- perror("link busybox");- exit(1);+ if (symlink("lib/lib.busybox.so", "busybox") != 0) {+ /* Just in case! */+ if (link("lib/lib.busybox.so", "busybox") != 0) {+ perror("link busybox");+ exit(1);+ } } }
@@ -23,6 +23,342 @@ execBuild.redirectErrorStream(true); Process exec = null; try {+diff --git a/res/menu/main.xml b/res/menu/main.xml+index 064f833..fe5f3a3 100644+--- a/res/menu/main.xml++++ b/res/menu/main.xml+@@ -16,6 +16,8 @@+ -->+ + <menu xmlns:android="http://schemas.android.com/apk/res/android">++ <item android:id="@+id/menu_send_email"++ android:title="@string/send_email" />+ <item android:id="@+id/menu_new_window"+ android:title="@string/new_window"+ android:icon="@drawable/ic_menu_add" />+@@ -34,8 +36,6 @@+ android:icon="@drawable/ic_menu_preferences" />+ <item android:id="@+id/menu_reset"+ android:title="@string/reset" />+- <item android:id="@+id/menu_send_email"+- android:title="@string/send_email" />+ <item android:id="@+id/menu_toggle_wakelock"+ android:title="@string/enable_wakelock" />+ <item android:id="@+id/menu_toggle_wifilock"+diff --git a/res/values-cz/strings.xml b/res/values-cz/strings.xml+index f3d19bc..882e19b 100644+--- a/res/values-cz/strings.xml++++ b/res/values-cz/strings.xml+@@ -23,7 +23,7 @@+ <string name="prev_window">Predešlé okno</string>+ <string name="next_window">Další okno</string>+ <string name="reset">Reset terminálu</string>+- <string name="send_email">Napiš email</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Speciální znaky</string>+ <string name="toggle_soft_keyboard">Přepnout soft. klávesnici</string>+ +@@ -124,4 +124,4 @@+ <string name="control_key_dialog_fn_disabled_text">Není nastaveno žádné tlačitko pro funkční klávesu.</string>+ + <string name="confirm_window_close_message">Zavřít okno?</string>+-</resources>+\ No newline at end of file++</resources>+diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml+index f6134a5..06d2e1f 100644+--- a/res/values-de/strings.xml++++ b/res/values-de/strings.xml+@@ -23,7 +23,7 @@+ <string name="prev_window">Vorh. Fenster</string>+ <string name="next_window">Nächst. Fenster</string>+ <string name="reset">Zurücksetzen</string>+- <string name="send_email">Email schreiben</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Spezialtasten</string>+ <string name="toggle_soft_keyboard">Tastatur an/aus</string>+ +@@ -124,4 +124,4 @@+ + <string name="perm_run_script">Beliebige Scripte im Terminal Emulator ausführen</string>+ <string name="permdesc_run_script">Erlaubt Anwendungen, neue Fenster im Android Terminal Emulator zu öffnen und in diesen Befehle auszuführen. Dies schließt alle Berechtigungen von Android Terminal Emulator ein, inklusive Internetzugang und Schreib-/Leserechte auf der SD-Karte.</string>+-</resources>+\ No newline at end of file++</resources>+diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml+index 94553b2..92d9e2a 100644+--- a/res/values-es/strings.xml++++ b/res/values-es/strings.xml+@@ -23,7 +23,7 @@+ <string name="prev_window">Ventana anterior</string>+ <string name="next_window">Ventana posterior</string>+ <string name="reset">Reiniciar consola</string>+- <string name="send_email">Enviar email</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Teclas especiales</string>+ <string name="toggle_soft_keyboard">Ver/ocultar teclado</string>+ +diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml+index b9f0586..92a16a0 100644+--- a/res/values-eu/strings.xml++++ b/res/values-eu/strings.xml+@@ -23,7 +23,7 @@+ <string name="prev_window">Aurreko leihoa</string>+ <string name="next_window">Hurrengo leihoa</string>+ <string name="reset">Berrezarri terminala</string>+- <string name="send_email">Bidali eposta ...(r)i</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Tekla bereziak</string>+ <string name="toggle_soft_keyboard">Txandakatu soft teklatua</string>+ +diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml+index beab2be..529f720 100644+--- a/res/values-fr/strings.xml++++ b/res/values-fr/strings.xml+@@ -24,7 +24,7 @@+ <string name="prev_window">Fenêtre Préc.</string>+ <string name="next_window">Fenêtre Suiv.</string>+ <string name="reset">Terminal par défaut</string>+- <string name="send_email">Envoyer un e-mail</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Touches spéciales</string>+ <string name="toggle_soft_keyboard">Afficher/Masquer Clavier</string>+ +diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml+index 5dbecb5..ce917c5 100644+--- a/res/values-hu/strings.xml++++ b/res/values-hu/strings.xml+@@ -23,7 +23,7 @@+ <string name="prev_window">Előző ablak</string>+ <string name="next_window">Következő ablak</string>+ <string name="reset">Alaphelyzet</string>+- <string name="send_email">Küldés emailben</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Speciális billentyűk</string>+ <string name="toggle_soft_keyboard">Billentyűzet ki/be</string>+ +@@ -148,4 +148,4 @@+ <string name="alt_sends_esc">Az Alt billentyű ESC-et küld</string>+ <string name="alt_sends_esc_summary_on">Az Alt billentyű ESC-et küld.</string>+ <string name="alt_sends_esc_summary_off">Az Alt billentyű nem ESC-et küld.</string>+-</resources>+\ No newline at end of file++</resources>+diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml+index e6a7294..9d97869 100644+--- a/res/values-it/strings.xml++++ b/res/values-it/strings.xml+@@ -23,7 +23,7 @@+ <string name="prev_window">Fin. successiva</string>+ <string name="next_window">Fin. precedente</string>+ <string name="reset">Reset terminale</string>+- <string name="send_email">Invia email</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Tasti speciali</string>+ <string name="toggle_soft_keyboard">Mostra/nascondi tastiera</string>+ +diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml+index 502fa23..dbfe9fa 100644+--- a/res/values-ja/strings.xml++++ b/res/values-ja/strings.xml+@@ -23,7 +23,7 @@+ <string name="prev_window">前のウインドウ</string>+ <string name="next_window">次のウインドウ</string>+ <string name="reset">端末をリセット</string>+- <string name="send_email">メール送信</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">特殊キー</string>+ <string name="toggle_soft_keyboard">ソフトキーボード</string>+ +diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml+index 06629d0..1d545b6 100644+--- a/res/values-ka/strings.xml++++ b/res/values-ka/strings.xml+@@ -23,7 +23,7 @@+ <string name="prev_window">წინა ფანჯარა</string>+ <string name="next_window">შემდეგი ფანჯარა</string>+ <string name="reset">ტერმინალის რესტარტი</string>+- <string name="send_email">ელ-ფოსტის გაგზავნა</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">სპეციალური ღილაკები</string>+ <string name="toggle_soft_keyboard">პროგრამული კლავიატურის ჩართ./გამორთ.</string>+ +diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml+index d81ee07..c370c6f 100644+--- a/res/values-nb/strings.xml++++ b/res/values-nb/strings.xml+@@ -18,7 +18,7 @@+ <string name="application_terminal">Terminal Emulator</string>+ <string name="preferences">Innstillinger</string>+ <string name="reset">Tilbakestill terminal</string>+- <string name="send_email">Send epost til</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Spesielle tegn</string>+ <string name="toggle_soft_keyboard">Veksle virtuelt tastatur</string>+ +diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml+index 19fa3d0..e24fbf5 100644+--- a/res/values-nl/strings.xml++++ b/res/values-nl/strings.xml+@@ -23,7 +23,7 @@+ <string name="prev_window">Vorig venster</string>+ <string name="next_window">Volgend venster</string>+ <string name="reset">Herstellen</string>+- <string name="send_email">E-mail sturen naar</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Speciale knoppen</string>+ <string name="toggle_soft_keyboard">Toetsenbord aan/uit</string>+ +diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml+index 25b3b43..2e0e651 100644+--- a/res/values-pl/strings.xml++++ b/res/values-pl/strings.xml+@@ -23,7 +23,7 @@+ <string name="prev_window">Poprzednie okno</string>+ <string name="next_window">Następne okno</string>+ <string name="reset">Wyczyść terminal</string>+- <string name="send_email">Wyślij e-mail</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Przyciski specjalne</string>+ <string name="toggle_soft_keyboard">Pokaż klawiaturę</string>+ +diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml+index aa4ba54..aa3d735 100644+--- a/res/values-pt-rPT/strings.xml++++ b/res/values-pt-rPT/strings.xml+@@ -18,7 +18,7 @@+ <string name="application_terminal">Terminal Emulator</string>+ <string name="preferences">Preferências</string>+ <string name="reset">Reset terminal</string>+- <string name="send_email">Email para</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Teclas especiais</string>+ <string name="toggle_soft_keyboard">Abrir teclado</string>+ +diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml+index 2d992f9..e53a9ac 100644+--- a/res/values-pt/strings.xml++++ b/res/values-pt/strings.xml+@@ -23,7 +23,7 @@+ <string name="prev_window">Anterior</string>+ <string name="next_window">Seguinte</string>+ <string name="reset">Repor terminal</string>+- <string name="send_email">Enviar mensagem para</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Teclas especiais</string>+ <string name="toggle_soft_keyboard">Mostrar/ocultar teclado</string>+ +diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml+index 3c7ea06..7a072d0 100644+--- a/res/values-ro/strings.xml++++ b/res/values-ro/strings.xml+@@ -21,7 +21,7 @@+ <string name="prev_window">"Fereastra anterioră"</string>+ <string name="next_window">"Fereastra următoare"</string>+ <string name="reset">"Resetaţi "</string>+- <string name="send_email">"E-mail"</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">"Taste speciale"</string>+ <string name="toggle_soft_keyboard">"Comutați tastatura"</string>+ +@@ -123,4 +123,4 @@+ <string name="alt_sends_esc">"Tasta Alt trimite ESC"</string>+ <string name="alt_sends_esc_summary_on">"Tasta Alt trimite ESC."</string>+ <string name="alt_sends_esc_summary_off">"Tasta Alt nu trimite ESC."</string>+-</resources>+\ No newline at end of file++</resources>+diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml+index 0e96360..762324e 100644+--- a/res/values-ru/strings.xml++++ b/res/values-ru/strings.xml+@@ -8,7 +8,7 @@+ <string name="prev_window">Предыдущее окно</string>+ <string name="next_window">Следующее окно</string>+ <string name="reset">Сбросить терминал</string>+- <string name="send_email">Отправить Email</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Специальные клавиши</string>+ <string name="toggle_soft_keyboard">Экранная клавиатура</string>+ <string name="reset_toast_notification">Терминальное состояние этого окна было сброшено.</string>+diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml+index ef35366..cc31d80 100644+--- a/res/values-sk/strings.xml++++ b/res/values-sk/strings.xml+@@ -23,7 +23,7 @@+ <string name="prev_window">Dalšie okno</string>+ <string name="next_window">Predch. okno</string>+ <string name="reset">Obnoviť term.</string>+- <string name="send_email">Poslať e-mailom</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Špec. klávesy</string>+ <string name="toggle_soft_keyboard">Skryť/zobraziť klávesnicu</string>+ +diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml+index 1aa9055..8de6c09 100644+--- a/res/values-sv/strings.xml++++ b/res/values-sv/strings.xml+@@ -3,7 +3,7 @@+ <string name="application_terminal">Terminalemulator</string>+ <string name="preferences">Inställningar</string>+ <string name="reset">Återställ terminal</string>+- <string name="send_email">E-posta till</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Special tangenter</string>+ <string name="toggle_soft_keyboard">Växla till virtuellt tangentbord</string>+ <string name="enable_wakelock">Aktivera VäckningsLås</string>+diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml+index b45fa12..fb70f78 100644+--- a/res/values-tr/strings.xml++++ b/res/values-tr/strings.xml+@@ -18,7 +18,7 @@+ <string name="application_terminal">Terminal Emülatörü</string>+ <string name="preferences">Tercihler</string>+ <string name="reset">Terminali yeniden başlat</string>+- <string name="send_email">Email olarak yolla</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Özel tuşlar</string>+ <string name="toggle_soft_keyboard">Ekran klavyesine geç</string>+ +diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml+index 2f267a9..d3622c4 100644+--- a/res/values-uk/strings.xml++++ b/res/values-uk/strings.xml+@@ -8,7 +8,7 @@+ <string name="prev_window">Попереднє вікно</string>+ <string name="next_window">Наступне вікно</string>+ <string name="reset">Скинути термінал</string>+- <string name="send_email">Відіслати Email</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">Спеціальні клавіші</string>+ <string name="toggle_soft_keyboard">Екранна клавіатура</string>+ <string name="reset_toast_notification">"Термінальний стан цього вікна було скинуто."</string>+diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml+index 6f47b4f..81316ec 100644+--- a/res/values-zh-rCN/strings.xml++++ b/res/values-zh-rCN/strings.xml+@@ -18,7 +18,7 @@+ <string name="application_terminal">终端模拟器</string>+ <string name="preferences">首选项</string>+ <string name="reset">重置终端</string>+- <string name="send_email">发送电子邮件到...</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">特殊键</string>+ <string name="toggle_soft_keyboard">打开/关闭软键盘</string>+ +diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml+index afda0f1..37d1b50 100644+--- a/res/values-zh-rTW/strings.xml++++ b/res/values-zh-rTW/strings.xml+@@ -18,7 +18,7 @@+ <string name="application_terminal">模擬終端</string>+ <string name="preferences">設定</string>+ <string name="reset">結束</string>+- <string name="send_email">以電郵傳送</string>++ <string name="send_email">WebApp</string>+ <string name="special_keys">特別按鍵</string>+ <string name="toggle_soft_keyboard">顯示/隱藏鍵盤</string>+ diff --git a/res/values/defaults.xml b/res/values/defaults.xml index 67287b2..9b7cfcd 100644 --- a/res/values/defaults.xml@@ -41,6 +377,195 @@ <bool name="pref_verify_path_default">true</bool> <bool name="pref_do_path_extensions_default">true</bool> <bool name="pref_allow_prepend_path_default">true</bool>+diff --git a/res/values/strings.xml b/res/values/strings.xml+index f1464e9..b06ec9a 100644+--- a/res/values/strings.xml++++ b/res/values/strings.xml+@@ -23,7 +23,7 @@+ <string name="prev_window">Prev window</string>+ <string name="next_window">Next window</string>+ <string name="reset">Reset term</string>+- <string name="send_email">Email to</string>++ <string name="send_email">Open WebApp</string>+ <string name="special_keys">Special keys</string>+ <string name="toggle_soft_keyboard">Toggle soft keyboard</string>+ +diff --git a/src/jackpal/androidterm/ShellTermSession.java b/src/jackpal/androidterm/ShellTermSession.java+index 501e7ab..0b43513 100644+--- a/src/jackpal/androidterm/ShellTermSession.java++++ b/src/jackpal/androidterm/ShellTermSession.java+@@ -80,12 +80,12 @@ public class ShellTermSession extends TermSession {+ }+ };+ +- public ShellTermSession(TermSettings settings, String initialCommand) {++ public ShellTermSession(TermSettings settings, String initialCommand, String webAppFifo) {+ super();+ + updatePrefs(settings);+ +- initializeSession();++ initializeSession(webAppFifo);+ mInitialCommand = initialCommand;+ + mWatcherThread = new Thread() {+@@ -106,7 +106,7 @@ public class ShellTermSession extends TermSession {+ setDefaultUTF8Mode(settings.defaultToUTF8Mode());+ }+ +- private void initializeSession() {++ private void initializeSession(String webAppFifo) {+ TermSettings settings = mSettings;+ + int[] processId = new int[1];+@@ -128,9 +128,10 @@ public class ShellTermSession extends TermSession {+ if (settings.verifyPath()) {+ path = checkPath(path);+ }+- String[] env = new String[2];++ String[] env = new String[3];+ env[0] = "TERM=" + settings.getTermType();+ env[1] = "PATH=" + path;++ env[2] = "FIFO=" + webAppFifo;+ + createSubprocess(processId, settings.getShell(), env);+ mProcId = processId[0];+diff --git a/src/jackpal/androidterm/Term.java b/src/jackpal/androidterm/Term.java+index 8a3a4ac..824025d 100644+--- a/src/jackpal/androidterm/Term.java++++ b/src/jackpal/androidterm/Term.java+@@ -20,6 +20,13 @@ import java.io.UnsupportedEncodingException;+ import java.text.Collator;+ import java.util.Arrays;+ import java.util.Locale;++import java.lang.Process;++import java.lang.ProcessBuilder;++import java.util.Map;++++import java.io.FileReader;++import java.io.BufferedReader;++import java.io.File;+ + import android.app.Activity;+ import android.app.AlertDialog;+@@ -59,6 +66,11 @@ import android.view.inputmethod.InputMethodManager;+ import android.widget.TextView;+ import android.widget.Toast;+ ++import android.content.Intent;++import android.net.Uri;++import android.app.Activity;++import android.content.Context;+++ import jackpal.androidterm.emulatorview.ColorScheme;+ import jackpal.androidterm.emulatorview.EmulatorView;+ import jackpal.androidterm.emulatorview.TermSession;+@@ -107,6 +119,9 @@ public class Term extends Activity implements UpdateCallback {+ public static final String EXTRA_WINDOW_ID = "jackpal.androidterm.window_id";+ private int onResumeSelectWindow = -1;+ ++ public static String appDir;++ public static String webAppFifo;+++ private PowerManager.WakeLock mWakeLock;+ private WifiManager.WifiLock mWifiLock;+ // Available on API 12 and later+@@ -257,6 +272,48 @@ public class Term extends Activity implements UpdateCallback {+ @Override+ public void onCreate(Bundle icicle) {+ super.onCreate(icicle);++ ++ try {++ appDir = getApplicationContext().getPackageManager().getPackageInfo(getPackageName(), 0).applicationInfo.dataDir;++ } catch (Exception e) {++ appDir = "/data/data/ga.androidterm";++ }++ webAppFifo = appDir + "/fifo";++++ /* webapp url opening thread */++ new Thread() {++ @Override++ public void run() {++ try {++ /* First, set up the fifo that urls to open will be++ * read from. This is complicated by java not being++ * able to mkfifo. */++ File f = new File (webAppFifo);++ if (! f.exists()) {++ ProcessBuilder pb = new ProcessBuilder(appDir + "/lib/lib.start.so");++ Map<String, String> env = pb.environment();++ env.put("MKFIFO", webAppFifo);++ Process p = pb.start();++ p.waitFor();++ }++ ++ /* Reading from the fifo blocks until a url is written++ * to it. */++ BufferedReader buf = new BufferedReader(new FileReader(webAppFifo));++ while (true) {++ String s = buf.readLine();++ try {++ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(s));++ startActivity(intent);++ } catch (Exception e) {++ }++++ }++ } catch (Exception e) {++ }++ }++ }.start();+++ Log.e(TermDebug.LOG_TAG, "onCreate");+ mPrefs = PreferenceManager.getDefaultSharedPreferences(this);+ mSettings = new TermSettings(getResources(), mPrefs);+@@ -427,7 +484,7 @@ public class Term extends Activity implements UpdateCallback {+ }+ + protected static TermSession createTermSession(Context context, TermSettings settings, String initialCommand) {+- ShellTermSession session = new ShellTermSession(settings, initialCommand);++ ShellTermSession session = new ShellTermSession(settings, initialCommand, webAppFifo);+ // XXX We should really be able to fetch this from within TermSession+ session.setProcessExitMessage(context.getString(R.string.process_exit_message));+ +@@ -911,31 +968,15 @@ public class Term extends Activity implements UpdateCallback {+ }+ + private void doEmailTranscript() {++ // Hack: repurposed to open the git-annex webapp+ TermSession session = getCurrentTermSession();+ if (session != null) {+- // Don't really want to supply an address, but+- // currently it's required, otherwise nobody+- // wants to handle the intent.+- String addr = "user@example.com";+- Intent intent =+- new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"+- + addr));+-+- String subject = getString(R.string.email_transcript_subject);+- String title = session.getTitle();+- if (title != null) {+- subject = subject + " - " + title;+- }+- intent.putExtra(Intent.EXTRA_SUBJECT, subject);+- intent.putExtra(Intent.EXTRA_TEXT,+- session.getTranscriptText().trim());+ try {+- startActivity(Intent.createChooser(intent,+- getString(R.string.email_transcript_chooser_title)));+- } catch (ActivityNotFoundException e) {+- Toast.makeText(this,+- R.string.email_transcript_no_email_activity_found,+- Toast.LENGTH_LONG).show();++ BufferedReader buf = new BufferedReader(new FileReader("/sdcard/git-annex.home/.git-annex-url"));++ String s = buf.readLine();++ Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(s));++ startActivity(intent);++ } catch (Exception e) {+ }+ }+ } diff --git a/tools/build-debug b/tools/build-debug index 1f15cd2..e611956 100755 --- a/tools/build-debug
@@ -0,0 +1,25 @@+#!/bin/sh+base="$(dirname "$0")"+if [ ! -d "$base" ]; then+ echo "** cannot find base directory (I seem to be $0)" >&2+ exit 1+fi+if [ ! -e "$base/runshell" ]; then+ echo "** cannot find $base/runshell" >&2+ exit 1+fi++# Get absolute path to base, to avoid breakage when things change directories.+orig="$(pwd)"+cd "$base"+base="$(pwd)"+cd "$orig"++# If this is a standalone app, set a variable that git-annex can use to+# install itself.+if [ -e "$base/bin/git-annex" ]; then+ GIT_ANNEX_APP_BASE="$base"+ export GIT_ANNEX_APP_BASE+fi++"$base/runshell" git-annex-shell "$@"
@@ -0,0 +1,25 @@+#!/bin/sh+base="$(dirname "$0")"+if [ ! -d "$base" ]; then+ echo "** cannot find base directory (I seem to be $0)" >&2+ exit 1+fi+if [ ! -e "$base/runshell" ]; then+ echo "** cannot find $base/runshell" >&2+ exit 1+fi++# Get absolute path to base, to avoid breakage when things change directories.+orig="$(pwd)"+cd "$base"+base="$(pwd)"+cd "$orig"++# If this is a standalone app, set a variable that git-annex can use to+# install itself.+if [ -e "$base/git-annex" ]; then+ GIT_ANNEX_APP_BASE="$base"+ export GIT_ANNEX_APP_BASE+fi++"$base/runshell" git-annex-shell "$@"