Repository: conda/conda-build

Issue:
incorrect sha256 for renamed script files when converting from Linux to Windows

### Actual Behavior

When converting the test package hello from Linux to Windows the sha256 hash for the renamed file "hello-script.py" is wrong. Installing the package on Windows throws a sha256 mismatch warning. The sha256 hash in the "info/paths.json" file is wrong for that file. If the package is generated on windows, the sha256 hash is correct.

### Expected Behavior
Correct sha256 hash value in "info/paths.json"

### Steps to Reproduce
Unpack the tar file attached into a temporary directory
Run the script "build_hello.sh" on Linux
It builds the package and converts it to several platforms
Check sha256 checksum in "info/paths.json" of the win-64 package version
[sha-problem.zip](https://github.com/conda/conda-build/files/1752522/sha-problem.zip)


##### `Output of conda info`


     active environment : None
     user config file : /home/achim/.condarc
     populated config files : /home/achim/.condarc
          conda version : 4.4.10
      conda-build version : 3.5.0
         python version : 3.6.4.final.0
       base environment : /home/achim/miniconda3  (writable)
           channel URLs : https://conda.anaconda.org/bug400/linux-64
                          https://conda.anaconda.org/bug400/noarch
                          https://repo.continuum.io/pkgs/main/linux-64
                          https://repo.continuum.io/pkgs/main/noarch
                          https://repo.continuum.io/pkgs/free/linux-64
                          https://repo.continuum.io/pkgs/free/noarch
                          https://repo.continuum.io/pkgs/r/linux-64
                          https://repo.continuum.io/pkgs/r/noarch
                          https://repo.continuum.io/pkgs/pro/linux-64
                          https://repo.continuum.io/pkgs/pro/noarch
          package cache : /home/achim/miniconda3/pkgs
                          /home/achim/.conda/pkgs
       envs directories : /home/achim/miniconda3/envs
                          /home/achim/.conda/envs
               platform : linux-64
             user-agent : conda/4.4.10 requests/2.18.4 CPython/3.6.4 Linux/4.13.0-36-generic neon/16.04 glibc/2.23
                UID:GID : 1101:1101
             netrc file : None
           offline mode : False





Discussion:
Thanks for reporting this.  We will fix it, but I'm not sure what the timeline is.  Because this is only a warning, I'm afraid it might need to wait a little while.
Could you give some pointers about where to look at to attempt to fix this ? I have seen the same issue and may find some time to help fix it.
Thanks @MatthieuDartiailh - it's going to be somewhere in convert.py, I'm guessing.  Here's one place we compute hashes for windows paths: https://github.com/conda/conda-build/blob/master/conda_build/convert.py#L324

Hopefully that helps you get started.
One quick question, is only the content of the file encoded in the sha or also its name (in the case of pure Python scripts, not the exe) ?
I believe it is only the content of the file.  If you find otherwise, let's discuss.
Ok thanks
I think I have a fix for this see #2713 
I installed conda-build 3.6.0 and built package under Linux. Installing the converted package on Windows 64 throws a warning that the converted script file has an incorrect size. The sha256 warning does not appear any more.
Likely need to compute the size of the converted script file here: 
https://github.com/conda/conda-build/blob/83cf30eb118024cf53fad35cf085d423ec0d4065/conda_build/convert.py#L362-L364

Resolving patch:
diff --git a/conda_build/convert.py b/conda_build/convert.py
--- a/conda_build/convert.py
+++ b/conda_build/convert.py
@@ -318,6 +318,20 @@ def update_executable_sha(package_directory, executable_path):
         return hashlib.sha256(script_file_contents).hexdigest()
 
 
+def update_executable_size(temp_dir, executable):
+    """Update the size of the converted executable files.
+
+    Positional arguments:
+    temp_dir (str) -- the file path to the temporary directory containing the source
+        package's extracted contents
+    executable (str) -- the executable whose size to update including its file extension
+
+    Returns:
+    byte size (int) of the executable file
+    """
+    return os.path.getsize(os.path.join(temp_dir, executable))
+
+
 def add_new_windows_path(executable_directory, executable):
     """Add a new path to the paths.json file.
 
@@ -362,6 +376,7 @@ def update_paths_file(temp_dir, target_platform):
                 elif path['_path'].startswith('bin'):
                     path['_path'] = update_executable_path(path['_path'], 'win')
                     path['sha256'] = update_executable_sha(temp_dir, path['_path'])
+                    path['size_in_bytes'] = update_executable_size(temp_dir, path['_path'])
 
             script_directory = os.path.join(temp_dir, 'Scripts')
             if os.path.isdir(script_directory):
@@ -377,6 +392,7 @@ def update_paths_file(temp_dir, target_platform):
                 elif path['_path'].startswith('Scripts'):
                     path['_path'] = update_executable_path(path['_path'], 'unix')
                     path['sha256'] = update_executable_sha(temp_dir, path['_path'])
+                    path['size_in_bytes'] = update_executable_size(temp_dir, path['_path'])
 
                 if path['_path'].endswith(('.bat', '.exe')):
                     paths['paths'].remove(path)


Test patch:
diff --git a/tests/test_api_convert.py b/tests/test_api_convert.py
--- a/tests/test_api_convert.py
+++ b/tests/test_api_convert.py
@@ -190,11 +190,13 @@ def test_convert_from_unix_to_win_creates_entry_points(testing_config):
         assert_package_consistency(converted_fn)
         paths_content = json.loads(package_has_file(converted_fn, 'info/paths.json').decode())
 
-        # Check the validity of the sha of the converted scripts
-        for f in paths_content['paths']:
-            if f['_path'].startswith('Scripts/') and f['_path'].endswith('-script.py'):
-                script_content = package_has_file(converted_fn, f['_path'])
-                assert f['sha256'] == hashlib.sha256(script_content).hexdigest()
+        # Check the validity of the sha and filesize of the converted scripts
+        with tarfile.open(converted_fn) as t:
+            for f in paths_content['paths']:
+                if f['_path'].startswith('Scripts/') and f['_path'].endswith('-script.py'):
+                    script_content = package_has_file(converted_fn, f['_path'])
+                    assert f['sha256'] == hashlib.sha256(script_content).hexdigest()
+                    assert f['size_in_bytes'] == t.getmember(f['_path']).size
 
         paths_list = {f['_path'] for f in paths_content['paths']}
         files = {p.decode() for p in package_has_file(converted_fn, 'info/files').splitlines()}