parameters: (source, entry, progress_cb)
return_statement: return None
docstring: Extract given image using rsync.
  
      :param source: Source file. This may be the place the entry's
          image is mounted, or if it's a single file, the entry's source value.
      :param entry: The UnpackEntry being copied.
      :param progress_cb: A callback function for progress reporting.
          Takes a number and a total-number.
docstring_summary: Extract given image using rsync.
docstring_tokens: Extract given image using rsync .
function: def file_copy(source, entry, progress_cb):
      """
      Extract given image using rsync.
  
      :param source: Source file. This may be the place the entry's
          image is mounted, or if it's a single file, the entry's source value.
      :param entry: The UnpackEntry being copied.
      :param progress_cb: A callback function for progress reporting.
          Takes a number and a total-number.
      """
      import time
  
      dest = entry.destination
  
      # `source` *must* end with '/' otherwise a directory named after the source
      # will be created in `dest`: ie if `source` is "/foo/bar" and `dest` is
      # "/dest", then files will be copied in "/dest/bar".
      if not source.endswith("/") and not os.path.isfile(source):
          source += "/"
  
      num_files_total_local = 0
      num_files_copied = 0  # Gets updated through rsync output
  
      args = ['rsync', '-aHAXr', '--filter=-x trusted.overlay.*']
      args.extend(global_excludes())
      if entry.excludeFile:
          args.extend(["--exclude-from=" + entry.excludeFile])
      if entry.exclude:
          for f in entry.exclude:
              args.extend(["--exclude", f])
      args.extend(['--progress', source, dest])
  
      # last_num_files_copied trails num_files_copied, and whenever at least 107 more
      # files (file_count_chunk) have been copied, progress is reported and
      # last_num_files_copied is updated. The chunk size isn't "tidy"
      # so that all the digits of the progress-reported number change.
      #
      file_count_chunk = 107
  
      class counter(object):
          last_num_files_copied = 0
          last_timestamp_reported = time.time()
          last_total_reported = 0
  
      def output_cb(line):
          # rsync outputs progress in parentheses. Each line will have an
          # xfer and a chk item (either ir-chk or to-chk) as follows:
          #
          # - xfer#x => Interpret it as 'file copy try no. x'
          # - ir-chk=x/y, where:
          #     - x = number of files yet to be checked
          #     - y = currently calculated total number of files.
          # - to-chk=x/y, which is similar and happens once the ir-chk
          #   phase (collecting total files) is over.
          #
          # If you're copying directory with some links in it, the xfer#
          # might not be a reliable counter (for one increase of xfer, many
          # files may be created).
          m = re.findall(r'xfr#(\d+), ..-chk=(\d+)/(\d+)', line)
  
          if m:
              # we've got a percentage update
              num_files_remaining = int(m[0][1])
              num_files_total_local = int(m[0][2])
              # adjusting the offset so that progressbar can be continuesly drawn
              num_files_copied = num_files_total_local - num_files_remaining
  
              now = time.time()
              if (num_files_copied - counter.last_num_files_copied >= file_count_chunk) or (now - counter.last_timestamp_reported > 0.5):
                  counter.last_num_files_copied = num_files_copied
                  counter.last_timestamp_reported = now
                  counter.last_total_reported = num_files_total_local
                  progress_cb(num_files_copied, num_files_total_local)
  
      try:
          returncode = libcalamares.utils.host_env_process_output(args, output_cb)
      except subprocess.CalledProcessError as e:
          returncode = e.returncode
  
      progress_cb(counter.last_num_files_copied, counter.last_total_reported)  # Push towards 100%
  
      # Mark this entry as really done
      entry.copied = entry.total
  
      # 23 is the return code rsync returns if it cannot write extended
      # attributes (with -X) because the target file system does not support it,
      # e.g., the FAT EFI system partition. We need -X because distributions
      # using file system capabilities and/or SELinux require the extended
      # attributes. But distributions using SELinux may also have SELinux labels
      # set on files under /boot/efi, and rsync complains about those. The only
      # clean way would be to split the rsync into one with -X and
      # --exclude /boot/efi and a separate one without -X for /boot/efi, but only
      # if /boot/efi is actually an EFI system partition. For now, this hack will
      # have to do. See also:
      # https://bugzilla.redhat.com/show_bug.cgi?id=868755#c50
      # for the same issue in Anaconda, which uses a similar workaround.
      if returncode != 0 and returncode != 23:
          libcalamares.utils.warning("rsync failed with error code {}.".format(returncode))
          return _("rsync failed with error code {}.").format(returncode)
  
      return None
function_tokens: def file_copy ( source , entry , progress_cb ) : import time dest = entry . destination # `source` *must* end with '/' otherwise a directory named after the source # will be created in `dest`: ie if `source` is "/foo/bar" and `dest` is # "/dest", then files will be copied in "/dest/bar". if not source . endswith ( "/" ) and not os . path . isfile ( source ) : source += "/" num_files_total_local = 0 num_files_copied = 0 # Gets updated through rsync output args = [ 'rsync' , '-aHAXr' , '--filter=-x trusted.overlay.*' ] args . extend ( global_excludes ( ) ) if entry . excludeFile : args . extend ( [ "--exclude-from=" + entry . excludeFile ] ) if entry . exclude : for f in entry . exclude : args . extend ( [ "--exclude" , f ] ) args . extend ( [ '--progress' , source , dest ] ) # last_num_files_copied trails num_files_copied, and whenever at least 107 more # files (file_count_chunk) have been copied, progress is reported and # last_num_files_copied is updated. The chunk size isn't "tidy" # so that all the digits of the progress-reported number change. # file_count_chunk = 107 class counter ( object ) : last_num_files_copied = 0 last_timestamp_reported = time . time ( ) last_total_reported = 0 def output_cb ( line ) : # rsync outputs progress in parentheses. Each line will have an # xfer and a chk item (either ir-chk or to-chk) as follows: # # - xfer#x => Interpret it as 'file copy try no. x' # - ir-chk=x/y, where: #     - x = number of files yet to be checked #     - y = currently calculated total number of files. # - to-chk=x/y, which is similar and happens once the ir-chk #   phase (collecting total files) is over. # # If you're copying directory with some links in it, the xfer# # might not be a reliable counter (for one increase of xfer, many # files may be created). m = re . findall ( r'xfr#(\d+), ..-chk=(\d+)/(\d+)' , line ) if m : # we've got a percentage update num_files_remaining = int ( m [ 0 ] [ 1 ] ) num_files_total_local = int ( m [ 0 ] [ 2 ] ) # adjusting the offset so that progressbar can be continuesly drawn num_files_copied = num_files_total_local - num_files_remaining now = time . time ( ) if ( num_files_copied - counter . last_num_files_copied >= file_count_chunk ) or ( now - counter . last_timestamp_reported > 0.5 ) : counter . last_num_files_copied = num_files_copied counter . last_timestamp_reported = now counter . last_total_reported = num_files_total_local progress_cb ( num_files_copied , num_files_total_local ) try : returncode = libcalamares . utils . host_env_process_output ( args , output_cb ) except subprocess . CalledProcessError as e : returncode = e . returncode progress_cb ( counter . last_num_files_copied , counter . last_total_reported ) # Push towards 100% # Mark this entry as really done entry . copied = entry . total # 23 is the return code rsync returns if it cannot write extended # attributes (with -X) because the target file system does not support it, # e.g., the FAT EFI system partition. We need -X because distributions # using file system capabilities and/or SELinux require the extended # attributes. But distributions using SELinux may also have SELinux labels # set on files under /boot/efi, and rsync complains about those. The only # clean way would be to split the rsync into one with -X and # --exclude /boot/efi and a separate one without -X for /boot/efi, but only # if /boot/efi is actually an EFI system partition. For now, this hack will # have to do. See also: # https://bugzilla.redhat.com/show_bug.cgi?id=868755#c50 # for the same issue in Anaconda, which uses a similar workaround. if returncode != 0 and returncode != 23 : libcalamares . utils . warning ( "rsync failed with error code {}." . format ( returncode ) ) return _ ( "rsync failed with error code {}." ) . format ( returncode ) return None