unison

Fork of Unison, a bi-directional file synchronization tool
git clone git://git.laack.co/unison.git
Log | Files | Refs | README | LICENSE

sortri.ml (5143B)


      1 (* Unison file synchronizer: src/sortri.ml *)
      2 (* Copyright 1999-2020, Benjamin C. Pierce
      3 
      4     This program is free software: you can redistribute it and/or modify
      5     it under the terms of the GNU General Public License as published by
      6     the Free Software Foundation, either version 3 of the License, or
      7     (at your option) any later version.
      8 
      9     This program is distributed in the hope that it will be useful,
     10     but WITHOUT ANY WARRANTY; without even the implied warranty of
     11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12     GNU General Public License for more details.
     13 
     14     You should have received a copy of the GNU General Public License
     15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16 *)
     17 
     18 
     19 open Common
     20 
     21 let dbgsort = Util.debug "sort"
     22 
     23 (* Preferences *)
     24 
     25 let bysize =
     26   Prefs.createBool "sortbysize" false
     27     ~category:(`Advanced `Syncprocess)
     28     "list changed files by size, not name"
     29     ("When this flag is set, the user interface will list changed files "
     30      ^ "by size (smallest first) rather than by name.  This is useful, for "
     31      ^ "example, for synchronizing over slow links, since it puts very "
     32      ^ "large files at the end of the list where they will not prevent "
     33      ^ "smaller files from being transferred quickly.\n\n"
     34      ^ "This preference (as well as the other sorting flags, but not the "
     35      ^ "sorting preferences that require patterns as arguments) can be "
     36      ^ "set interactively and temporarily using the 'Sort' menu in the "
     37      ^ "graphical and text user interfaces.")
     38 
     39 let newfirst =
     40   Prefs.createBool "sortnewfirst" false
     41     ~category:(`Advanced `Syncprocess)
     42     "list new before changed files"
     43     ("When this flag is set, the user interface will list newly created "
     44      ^ "files before all others.  This is useful, for example, for checking "
     45      ^ "that newly created files are not `junk', i.e., ones that should be "
     46      ^ "ignored or deleted rather than synchronized.")
     47 
     48 let sortfirst = Pred.create "sortfirst"
     49     ~category:(`Advanced `Syncprocess)
     50     ("Each argument to \\texttt{sortfirst} is a pattern \\ARG{pathspec}, "
     51      ^ "which describes a set of paths.  "
     52      ^ "Files matching any of these patterns will be listed first in the "
     53      ^ "user interface. "
     54      ^ "The syntax of \\ARG{pathspec} is "
     55      ^ "described in \\sectionref{pathspec}{Path Specification}.")
     56 
     57 let sortlast = Pred.create "sortlast"
     58     ~category:(`Advanced `Syncprocess)
     59     ("Similar to \\verb|sortfirst|, except that files matching one of these "
     60      ^ "patterns will be listed at the very end.")
     61 
     62 type savedPrefs = {nf:bool; bs:bool; sf:string list; sl:string list}
     63 let savedPrefs = ref(None)
     64 
     65 let saveSortingPrefs () =
     66   if !savedPrefs = None then
     67     savedPrefs := Some {
     68       sf = Pred.extern sortfirst;
     69       sl = Pred.extern sortlast;
     70       bs = Prefs.read bysize;
     71       nf = Prefs.read newfirst }
     72 
     73 let restoreDefaultSettings () =
     74   match !savedPrefs with
     75     None -> ()
     76   | Some {nf=nf; bs=bs; sf=sf; sl=sl} ->
     77       Prefs.set newfirst nf;
     78       Prefs.set bysize bs;
     79       Pred.intern sortfirst sf;
     80       Pred.intern sortlast sl
     81 
     82 let zeroSortingPrefs () =
     83   Prefs.set newfirst false;
     84   Prefs.set bysize false;
     85   Pred.intern sortfirst [];
     86   Pred.intern sortlast []
     87 
     88 (* ------------------- *)
     89 
     90 let sortByName () =
     91   saveSortingPrefs();
     92   zeroSortingPrefs()
     93 
     94 let sortBySize () =
     95   saveSortingPrefs();
     96   zeroSortingPrefs();
     97   Prefs.set bysize true
     98 
     99 let sortNewFirst () =
    100   saveSortingPrefs();
    101   Prefs.set newfirst (not (Prefs.read newfirst))
    102 
    103 (* ---------------------------------------------------------------------- *)
    104 (* Main sorting functions *)
    105 
    106 let shouldSortFirst ri =
    107   Pred.test sortfirst (Path.toString ri.path1)
    108 let shouldSortLast ri =
    109   Pred.test sortlast (Path.toString ri.path1)
    110 
    111 let newItem ri =
    112   let newItem1 ri =
    113     match ri.replicas with
    114       Different diff -> diff.rc1.status = `Created
    115     | _ -> false in
    116   let newItem2 ri =
    117     match ri.replicas with
    118       Different diff -> diff.rc2.status = `Created
    119     | _ -> false
    120   in newItem1 ri || newItem2 ri
    121 
    122 (* Should these go somewhere else? *)
    123 let rec combineCmp = function
    124     [] -> 0
    125   | c::cs -> if c<>0 then c else combineCmp cs
    126 let invertCmp c = c * -1
    127 
    128 let compareReconItems () =
    129   let newfirst = Prefs.read newfirst in
    130   fun ri1 ri2 ->
    131     let pred p =
    132       let b1 = p ri1 in let b2 = p ri2 in
    133       if b1 && b2 then 0 else if b1 then -1 else if b2 then 1 else 0 in
    134     let cmp =
    135       combineCmp [
    136         pred problematic;
    137         pred partiallyProblematic;
    138         pred shouldSortFirst;
    139         invertCmp (pred shouldSortLast);
    140         if newfirst then pred newItem else 0;
    141         (if Prefs.read bysize then
    142           let l1 = Common.riLength ri1 in
    143           let l2 = Common.riLength ri2 in
    144           if l1<l2 then -1 else if l2<l1 then 1 else 0
    145          else 0);
    146         (compare (Path.toString ri1.path1) (Path.toString ri2.path1))
    147       ] in
    148     dbgsort (fun() -> Util.msg "%s <= %s --> %d\n"
    149                (Path.toString ri1.path1) (Path.toString ri2.path1) cmp);
    150     cmp
    151 
    152 let sortReconItems items = Safelist.stable_sort (compareReconItems()) items