bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: gnulib-tool: don't use hard links


From: Bruno Haible
Subject: Re: gnulib-tool: don't use hard links
Date: Mon, 22 May 2017 01:41:21 +0200
User-agent: KMail/5.1.3 (Linux/4.4.0-75-generic; KDE/5.18.0; x86_64; ; )

> > for other 
> > stuff that I'm working on, where the default value 'ask' is often the right 
> > thing to do.
> 
> Well, in this case, if for other projects 'ask' is better, I'll implement
> the options -h / --hardlink, -H / --more-hardlinks.

Implemented as follows:



2017-05-21  Bruno Haible  <address@hidden>

        gnulib-tool: Add options to create hard links.
        * gnulib-tool (func_usage): Document options --hardlink,
        --local-hardlink, --more-hardlinks.
        (func_symlink): Renamed from func_ln.
        (func_symlink_if_changed): Renamed from func_ln_if_changed.
        (func_hardlink): New function.
        (copymode, lcopymode): New variables.
        (symbolic, lsymbolic): Remove variables.
        (Options): Implement options --hardlink, --local-hardlink,
        --more-hardlinks.
        (func_should_link): Renamed from func_should_symlink. Set copyaction.
        (func_add_file, func_update_file): Update invocation of
        func_should_link. Invoke func_hardlink when appropriate.
        (func_import): Update comments.
        (func_create_testdir): Update invocation of func_should_link. Invoke
        func_hardlink when appropriate.
        Finally, invoke 'git update-index --refresh' to mitigate the effects of
        the hard links on git.

diff --git a/gnulib-tool b/gnulib-tool
index c5b993a..a0dc037 100755
--- a/gnulib-tool
+++ b/gnulib-tool
@@ -295,11 +295,16 @@ Options for --import, --add/remove-import, --update,
   -s, --symbolic, --symlink Make symbolic links instead of copying files.
       --local-symlink       Make symbolic links instead of copying files, only
                             for files from the local override directory.
+  -h, --hardlink            Make hard links instead of copying files.
+      --local-hardlink      Make hard links instead of copying files, only
+                            for files from the local override directory.
 
 Options for --import, --add/remove-import, --update:
 
   -S, --more-symlinks       Make symbolic links instead of copying files, and
                             don't replace copyright notices.
+  -H, --more-hardlinks      Make hard links instead of copying files, and
+                            don't replace copyright notices.
 
 Report bugs to <address@hidden>."
 }
@@ -788,10 +793,10 @@ func_ln_s ()
   }
 }
 
-# func_ln SRC DEST
+# func_symlink SRC DEST
 # Like func_ln_s, except that SRC is given relative to the current directory 
(or
 # absolute), not given relative to the directory of DEST.
-func_ln ()
+func_symlink ()
 {
   case "$1" in
     /* | ?:*)
@@ -811,22 +816,34 @@ func_ln ()
   esac
 }
 
-# func_ln_if_changed SRC DEST
-# Like func_ln, but avoids munging timestamps if the link is correct.
-func_ln_if_changed ()
+# func_symlink_if_changed SRC DEST
+# Like func_symlink, but avoids munging timestamps if the link is correct.
+# SRC is given relative to the current directory (or absolute).
+func_symlink_if_changed ()
 {
   if test $# -ne 2; then
-    echo "usage: func_ln_if_changed SRC DEST" >&2
+    echo "usage: func_symlink_if_changed SRC DEST" >&2
   fi
   ln_target=`func_readlink "$2"`
   if test -h "$2" && test "$1" = "$ln_target"; then
     :
   else
     rm -f "$2"
-    func_ln "$1" "$2"
+    func_symlink "$1" "$2"
   fi
 }
 
+# func_hardlink SRC DEST
+# Like ln, except use cp -p if ln fails.
+# SRC is given relative to the current directory (or absolute).
+func_hardlink ()
+{
+  ln "$1" "$2" || {
+    echo "$progname: ln failed; falling back on cp -p" >&2
+    cp -p "$1" "$2"
+  }
+}
+
 # Ensure an 'echo' command that
 #   1. does not interpret backslashes and
 #   2. does not print an error message "broken pipe" when writing into a pipe
@@ -1052,10 +1069,14 @@ func_determine_path_separator
 #                   given, blank otherwise
 # - autoconf_minversion  minimum supported autoconf version
 # - doit            : if actions shall be executed, false if only to be printed
-# - symbolic        true if --symlink or --more-symlinks was given, blank
-#                   otherwise
-# - lsymbolic       true if --local-symlink was given, blank otherwise
-# - do_copyrights   blank if --more-symlinks was given, true otherwise
+# - copymode        symlink if --symlink or --more-symlinks was given,
+#                   hardlink if --hardlink or --more-hardlinks was given,
+#                   blank otherwise
+# - lcopymode       symlink if --local-symlink was given,
+#                   hardlink if --local-hardlink was given,
+#                   blank otherwise
+# - do_copyrights   blank if --more-symlinks or --more-hardlinks was given,
+#                   true otherwise
 {
   mode=
   destdir=
@@ -1093,8 +1114,8 @@ func_determine_path_separator
   witness_c_macro=
   vc_files=
   doit=:
-  symbolic=
-  lsymbolic=
+  copymode=
+  lcopymode=
   do_copyrights=true
 
   supplied_opts="$@"
@@ -1371,16 +1392,26 @@ func_determine_path_separator
         doit=false
         shift ;;
       -s | --symbolic | --symboli | --symbol | --symbo | --symb | --symlink | 
--symlin | --symli | --syml | --sym | --sy )
-        symbolic=true
+        copymode=symlink
         shift ;;
       --local-symlink | --local-symlin | --local-symli | --local-syml | 
--local-sym | --local-sy | --local-s )
-        lsymbolic=true
+        lcopymode=symlink
         shift ;;
-      -S | --more-symlinks | --more-symlink | --more-symlin | --more-symli | 
--more-syml | --more-sym | --more-sy | --more-s | --more- | --more | --mor | 
--mo )
-        symbolic=true
+      -h | --hardlink | --hardlin | --hardli | --hardl | --hard | --har | --ha 
)
+        copymode=hardlink
+        shift ;;
+      --local-hardlink | --local-hardlin | --local-hardli | --local-hardl | 
--local-hard | --local-har | --local-ha | --local-h )
+        lcopymode=hardlink
+        shift ;;
+      -S | --more-symlinks | --more-symlink | --more-symlin | --more-symli | 
--more-syml | --more-sym | --more-sy | --more-s )
+        copymode=symlink
+        do_copyrights=
+        shift ;;
+      -H | --more-hardlinks | --more-hardlink | --more-hardlin | --more-hardli 
| --more-hardl | --more-hard | --more-har | --more-ha | --more-h )
+        copymode=hardlink
         do_copyrights=
         shift ;;
-      --help | --hel | --he | --h )
+      --help | --hel | --he )
         func_usage
         func_exit $? ;;
       --version | --versio | --versi | --vers )
@@ -3302,19 +3333,26 @@ func_is_local_file ()
   func_path_foreach "$local_gnulib_path" test %dir% = "$dname"
 }
 
-# func_should_symlink
-# returns 0 when the file $f should be symlinked
+# func_should_link
+# determines whether the file $f should be copied, symlinked, or hardlinked.
 # Input:
-# - symbolic        true if files should be symlinked, copied otherwise
-# - lsymbolic       true if files from local_gnulib_path should be symlinked,
-#                   copied otherwise
+# - copymode        copy mode for files in general
+# - lcopymode       copy mode for files from local_gnulib_path
 # - f               the original file name
 # - lookedup_file   name of the merged (combined) file
-func_should_symlink ()
+# Sets variable:
+# - copyaction      copy or symlink or hardlink
+func_should_link ()
 {
-  test -n "$symbolic" \
-    || { test -n "$lsymbolic" \
-         && func_is_local_file "$lookedup_file" "$f"; }
+  if test -n "$lcopymode" && func_is_local_file "$lookedup_file" "$f"; then
+    copyaction="$lcopymode"
+  else
+    if test -n "$copymode"; then
+      copyaction="$copymode"
+    else
+      copyaction=copy
+    fi
+  fi
 }
 
 # func_add_file
@@ -3330,19 +3368,25 @@ func_should_symlink ()
 # - g               the rewritten file name
 # - tmpfile         absolute filename of the temporary file
 # - doit            : if actions shall be executed, false if only to be printed
-# - symbolic        true if files should be symlinked, copied otherwise
-# - lsymbolic       true if files from local_gnulib_path should be symlinked,
-#                   copied otherwise
+# - copymode        copy mode for files in general
+# - lcopymode       copy mode for files from local_gnulib_path
 func_add_file ()
 {
   if $doit; then
     echo "Copying file $g"
-    if func_should_symlink \
+    func_should_link
+    if test "$copyaction" = symlink \
        && test -z "$lookedup_tmp" \
        && cmp -s "$lookedup_file" "$tmpfile"; then
-      func_ln_if_changed "$lookedup_file" "$destdir/$g"
+      func_symlink_if_changed "$lookedup_file" "$destdir/$g"
     else
-      mv -f "$tmpfile" "$destdir/${g}" || func_fatal_error "failed"
+      if test "$copyaction" = hardlink \
+         && test -z "$lookedup_tmp" \
+         && cmp -s "$lookedup_file" "$tmpfile"; then
+        func_hardlink "$lookedup_file" "$destdir/$g"
+      else
+        mv -f "$tmpfile" "$destdir/${g}" || func_fatal_error "failed"
+      fi
     fi
   else
     echo "Copy file $g"
@@ -3362,9 +3406,8 @@ func_add_file ()
 # - g               the rewritten file name
 # - tmpfile         absolute filename of the temporary file
 # - doit            : if actions shall be executed, false if only to be printed
-# - symbolic        true if files should be symlinked, copied otherwise
-# - lsymbolic       true if files from local_gnulib_path should be symlinked,
-#                   copied otherwise
+# - copymode        copy mode for files in general
+# - lcopymode       copy mode for files from local_gnulib_path
 # - already_present  nonempty if the file should already exist, empty otherwise
 func_update_file ()
 {
@@ -3379,12 +3422,19 @@ func_update_file ()
         echo "Replacing file $g (non-gnulib code backed up in ${g}~) !!"
       fi
       mv -f "$destdir/$g" "$destdir/${g}~" || func_fatal_error "failed"
-      if func_should_symlink \
+      func_should_link
+      if test "$copyaction" = symlink \
          && test -z "$lookedup_tmp" \
          && cmp -s "$lookedup_file" "$tmpfile"; then
-        func_ln_if_changed "$lookedup_file" "$destdir/$g"
+        func_symlink_if_changed "$lookedup_file" "$destdir/$g"
       else
-        mv -f "$tmpfile" "$destdir/${g}" || func_fatal_error "failed"
+        if test "$copyaction" = hardlink \
+           && test -z "$lookedup_tmp" \
+           && cmp -s "$lookedup_file" "$tmpfile"; then
+          func_hardlink "$lookedup_file" "$destdir/$g"
+        else
+          mv -f "$tmpfile" "$destdir/${g}" || func_fatal_error "failed"
+        fi
       fi
     else
       if test -n "$already_present"; then
@@ -4408,9 +4458,8 @@ func_reconstruct_cached_local_gnulib_path ()
 #                   given, blank otherwise
 # - autoconf_minversion  minimum supported autoconf version
 # - doit            : if actions shall be executed, false if only to be printed
-# - symbolic        true if files should be symlinked, copied otherwise
-# - lsymbolic       true if files from local_gnulib_path should be symlinked,
-#                   copied otherwise
+# - copymode        copy mode for files in general
+# - lcopymode       copy mode for files from local_gnulib_path
 # - do_copyrights   true if copyright notices in files should be replaced,
 #                   blank otherwise
 func_import ()
@@ -4964,7 +5013,7 @@ s,^\(.................................................[^ 
]*\) *,
     exec 0<&5 5<&-
   }
 
-  # Copy files or make symbolic links. Remove obsolete files.
+  # Copy files or make symbolic links or hard links. Remove obsolete files.
   added_files=''
   removed_files=''
   delimiter='  '
@@ -5887,9 +5936,8 @@ s,//*$,/,'
 #                      --no-conditional-dependencies was given, blank otherwise
 # - libtool         true if --libtool was given, false if --no-libtool was
 #                   given, blank otherwise
-# - symbolic        true if files should be symlinked, copied otherwise
-# - lsymbolic       true if files from local_gnulib_path should be symlinked,
-#                   copied otherwise
+# - copymode        copy mode for files in general
+# - lcopymode       copy mode for files from local_gnulib_path
 func_create_testdir ()
 {
   testdir="$1"
@@ -6067,7 +6115,7 @@ func_create_testdir ()
     exec 0<&5 5<&-
   }
 
-  # Copy files or make symbolic links.
+  # Copy files or make symbolic links or hard links.
   delimiter='  '
   for f in $files; do echo $f; done \
     | sed -e "s,^.*\$,&$delimiter&," -e "$sed_rewrite_files" \
@@ -6084,10 +6132,15 @@ func_create_testdir ()
       if test -n "$lookedup_tmp"; then
         cp -p "$lookedup_file" "$testdir/$g"
       else
-        if func_should_symlink; then
-          func_ln "$lookedup_file" "$testdir/$g"
+        func_should_link
+        if test "$copyaction" = symlink; then
+          func_symlink "$lookedup_file" "$testdir/$g"
         else
-          cp -p "$lookedup_file" "$testdir/$g"
+          if test "$copyaction" = hardlink; then
+            func_hardlink "$lookedup_file" "$testdir/$g"
+          else
+            cp -p "$lookedup_file" "$testdir/$g"
+          fi
         fi
       fi
     done
@@ -7057,6 +7110,17 @@ s/\([.*$]\)/[\1]/g'
     func_fatal_error "unknown operation mode --$mode" ;;
 esac
 
+if test "$copymode" = hardlink -o "$lcopymode" = hardlink; then
+  # Setting hard links modifies the ctime of files in the gnulib checkout.
+  # This disturbs the result of the next "gitk" invocation.
+  # Workaround: Let git scan the files. This can be done through
+  # "git update-index --refresh" or "git status" or "git diff".
+  if test -d "$gnulib_dir"/.git \
+     && (git --version) >/dev/null 2>/dev/null; then
+    (cd "$gnulib_dir" && git update-index --refresh >/dev/null)
+  fi
+fi
+
 rm -rf "$tmp"
 # Undo the effect of the previous 'trap' command. Some shellology:
 # We cannot use "trap - 0 1 2 3 13 15", because Solaris sh would attempt to




reply via email to

[Prev in Thread] Current Thread [Next in Thread]