private function generate_diff( $product, $files, $recurse = false ) {
		require_once( ABSPATH . 'wp-admin/includes/file.php' );
		WP_Filesystem();
		global $wp_filesystem;

		$diff = array();
		$path = str_replace( ABSPATH, $wp_filesystem->abspath(), plugin_dir_path( $product->get_basefile() ) );
		$list = $wp_filesystem->dirlist( $path, false, $recurse );
		// nothing found.
		if ( ! $list ) {
			return $diff;
		}
		$list = array_keys( self::flatten_dirlist( $list ) );

		// now let's get the valid files that actually exist.
		if ( empty( $files ) ) {
			$files = $list;
		} else {
			$files = array_intersect( $files, $list );
		}

		// fetch the calculated hashes.
		if ( ! $wp_filesystem->is_readable( $path . '/' . self::HASH_FILE ) ) {
			return new WP_Error( 'themeisle_sdk_hash_not_found', sprintf( '%s not found', self::HASH_FILE ) );
		}

		$hashes = json_decode( $wp_filesystem->get_contents( $path . '/' . self::HASH_FILE ), true );
		ksort( $hashes );

		$diff = array();
		foreach ( $files as $file ) {
			// file does not exist in the hashes.
			if ( ! array_key_exists( $file, $hashes ) ) {
				continue;
			}
			$new = md5( $wp_filesystem->get_contents( $path . $file ) );
			$old = $hashes[ $file ];

			// same hash, bail.
			if ( $new === $old ) {
				continue;
			}
			$diff[] = $file;
		}

		return $diff;
	}