diff options
| author | Mirek Kratochvil <exa.exa@gmail.com> | 2026-09-10 16:42:26 +0200 |
|---|---|---|
| committer | Mirek Kratochvil <exa.exa@gmail.com> | 2026-09-10 16:42:26 +0200 |
| commit | 9e81c17e3dc5acfce46da91369b52974c525e5ff (patch) | |
| tree | 6bc28ac71821e6661a094d0c12c5c98075b48ba0 | |
| download | git-auto-acp-9e81c17e3dc5acfce46da91369b52974c525e5ff.tar.gz git-auto-acp-9e81c17e3dc5acfce46da91369b52974c525e5ff.tar.bz2 | |
initial undebugged version
| -rw-r--r-- | LICENSE | 165 | ||||
| -rw-r--r-- | Main.hs | 164 | ||||
| -rw-r--r-- | git-auto-acp.cabal | 39 |
3 files changed, 368 insertions, 0 deletions
@@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. @@ -0,0 +1,164 @@ +{-# LANGUAGE ApplicativeDo #-} +{-# LANGUAGE RecordWildCards #-} + +module Main + ( main + ) where + +import Data.Version (showVersion) +import Paths_git_auto_acp (version) + +import Control.Concurrent +import Control.Monad +import Data.Foldable +import Data.Maybe +import qualified Data.Set as S +import Options.Applicative +import System.Clock +import System.Environment +import System.Exit +import System.FSNotify +import System.FilePath.Glob +import System.IO +import System.Process + +data Watch = Watch + { watchPath :: FilePath + , watchWithRemoval :: Bool + } deriving (Show, Eq, Ord) + +data Opts = Opts + { optAddCommitDelay :: Float + , optPushDelay :: Maybe Float + , optWatches :: [Watch] + , optMsg :: String + } deriving (Show) + +opts :: Parser Opts +opts = do + optAddCommitDelay <- + option auto + $ short 'd' + <> long "commit-delay" + <> help "debuounce delay for adding and commiting new changes" + <> value 5 + <> showDefault + optPushDelay <- + asum + [ flag' Nothing + $ short 'L' <> long "local" <> help "only work locally, do not push" + , fmap Just . option auto + $ short 'D' + <> long "push-delay" + <> help "push changes upstream with this debuounce delay" + <> value 60 + <> showDefault + ] + optWatches <- + some + $ asum + [ fmap (`Watch` False) . strOption + $ short 'a' + <> long "add" + <> metavar "PATH" + <> help "paths to auto-add" + , fmap (`Watch` False) . strOption + $ short 'A' + <> long "add-all" + <> metavar "PATH" + <> help "like `--add' but auto-adds file removals" + ] + optMsg <- + strOption + $ short 'm' + <> long "message" + <> metavar "MSG" + <> help "commit message for auto-commits" + <> value "update to filesystem state" + <> showDefault + pure Opts {..} + +data Event + = AddBounce + | PushBounce + | Change Watch + | Finished + deriving (Show, Eq, Ord) + +delaySec :: Float -> IO () +delaySec = threadDelay . round . (1000000 *) + +intervalPassed i a b = + 1000000000 * i <= fromIntegral (toNanoSecs $ diffTimeSpec a b) + +runCmd prog args = do + st <- rawSystem prog args + unless (st == ExitSuccess) . hPutStrLn stderr + $ prog ++ " failed with args " ++ show args + +main :: IO () +main = do + o <- + customExecParser (prefs $ showHelpOnEmpty) + $ info + (opts <**> helper <**> simpleVersioner (showVersion version)) + (fullDesc + <> header "git-auto-acp -- automatically add-commit-push files" + <> (footer + "This program is free software; see LICENSE file for details.")) + git <- fromMaybe "git" <$> lookupEnv "AUTO_ACP_GIT" + withManager $ \fsmgr -> do + chan <- newChan + done <- newEmptyMVar + -- start some watchers + for_ (optWatches o) $ \w@(Watch path _) -> + watchTree fsmgr path (const True) . const $ writeChan chan (Change w) + -- start the event crunching thread + forkIO + $ let loop ws lastAdd addsPending lastPush pushesPending = do + ev <- readChan chan + now <- getTime Monotonic + case ev of + Finished -> pure () + Change w -> do + forkIO + $ delaySec (optAddCommitDelay o) >> writeChan chan AddBounce + let ws' = S.insert w ws + case optPushDelay o of + Nothing -> + loop ws' lastAdd (succ addsPending) lastPush pushesPending + Just pd -> do + forkIO $ delaySec pd >> writeChan chan PushBounce + loop + ws' + lastAdd + (succ addsPending) + lastPush + (succ pushesPending) + AddBounce + | not (S.null ws) + , addsPending == 1 + || intervalPassed (optAddCommitDelay o) now lastAdd -> do + for_ ws $ \(Watch p all) -> do + if all + then runCmd git ["add", p] + else runCmd git ["add", "--all", p] + runCmd git ["commit", "--message", optMsg o] + loop S.empty now (pred addsPending) lastPush pushesPending + | otherwise -> + loop + S.empty + lastAdd + (pred addsPending) + lastPush + pushesPending + PushBounce + | Just pd <- optPushDelay o + , pushesPending == 1 || intervalPassed pd now lastPush -> do + runCmd git ["push"] + loop ws lastAdd addsPending now (pred pushesPending) + | otherwise -> + loop ws lastAdd addsPending lastPush (pred pushesPending) + in loop S.empty 0 0 0 0 + -- wait for the finish, then terminate + takeMVar done diff --git a/git-auto-acp.cabal b/git-auto-acp.cabal new file mode 100644 index 0000000..47aafe8 --- /dev/null +++ b/git-auto-acp.cabal @@ -0,0 +1,39 @@ +cabal-version: 3.0 +name: git-auto-acp +version: 0.1.0.0 +synopsis: + auto-git-add-commit-push over a watched directory, via filesystems notifications + +license: LGPL-3.0-or-later +license-file: LICENSE +author: Mirek Kratochvil +maintainer: exa.exa@gmail.com +copyright: (C) 2026 Mirek Kratochvil +category: Development +build-type: Simple +extra-doc-files: + CHANGELOG.md + README.md + +-- extra-source-files: + +common warnings + ghc-options: -Wall + +executable git-auto-acp + import: warnings + main-is: Main.hs + autogen-modules: Paths_git_auto_acp + other-modules: Paths_git_auto_acp + build-depends: + , base >=4.17 && <5 + , clock + , containers + , filepath + , fsnotify + , Glob + , optparse-applicative + , process + + hs-source-dirs: . + default-language: Haskell2010 |
