Skip to content

Commit db42039

Browse files
author
Stewart Miles
committed
Fixed export_unity_package.py path issues on Windows.
Normalized all paths to use POSIX separators and fixed tests to handle different file mode behavior on Windows. Change-Id: I1ee231fc5b68024dee150809df97fe26818ecb9f
1 parent 594ff6d commit db42039

File tree

2 files changed

+49
-31
lines changed

2 files changed

+49
-31
lines changed

Diff for: source/ExportUnityPackage/export_unity_package.py

+29-16
Original file line numberDiff line numberDiff line change
@@ -541,13 +541,11 @@
541541
LINUX_SHARED_LIBRARY_EXTENSION = ".so"
542542
# Path relative to the "Assets" dir of native Linux plugin libraries.
543543
LINUX_SHARED_LIBRARY_PATH = re.compile(
544-
r"^Plugins{sep}(x86|x86_64){sep}(.*{ext})".format(
545-
sep=os.path.sep,
544+
r"^Plugins/(x86|x86_64)/(.*{ext})".format(
546545
ext=LINUX_SHARED_LIBRARY_EXTENSION.replace(".", r"\.")))
547546
# Path components required for native desktop libraries.
548547
SHARED_LIBRARY_PATH = re.compile(
549-
(r"(^|{sep})Plugins{sep}(x86|x86_64){sep}(.*{sep}|)[^{sep}]+"
550-
r"\.(so|dll|bundle)$").format(sep=os.path.sep))
548+
r"(^|/)Plugins/(x86|x86_64)/(.*/|)[^/]+\.(so|dll|bundle)$")
551549
# Prefix of the keywords to be added to UPM manifest to link to legacy manifest.
552550
UPM_KEYWORDS_MANIFEST_PREFIX = "vh-name:"
553551
# Everything in a Unity plugin - at the moment - lives under the Assets
@@ -570,6 +568,17 @@
570568
STR_OR_UNICODE = [str]
571569
unicode = str # pylint: disable=redefined-builtin,invalid-name
572570

571+
def posix_path(path):
572+
"""Convert path separators to POSIX style.
573+
574+
Args:
575+
path: Path to convert.
576+
577+
Returns:
578+
Path with POSIX separators, i.e / rather than \\.
579+
"""
580+
return path.replace('\\', '/')
581+
573582

574583
class MissingGuidsError(Exception):
575584
"""Raised when GUIDs are missing for input files in export_package().
@@ -638,7 +647,7 @@ def add_guid_and_path(self, guid, path):
638647
guid: GUID to add to this instance.
639648
path: Path associated with this GUID.
640649
"""
641-
self._paths_by_guid[guid].add(path)
650+
self._paths_by_guid[guid].add(posix_path(path))
642651

643652
def check_for_duplicates(self):
644653
"""Check the set of GUIDs for duplicate paths.
@@ -960,7 +969,7 @@ def __init__(self, duplicate_guids_checker, guids_json,
960969
guid_map = safe_dict_get_value(guids_json, plugin_version,
961970
default_value={})
962971
for filename, guid in guid_map.items():
963-
self.add_guid(filename, guid)
972+
self.add_guid(posix_path(filename), guid)
964973

965974
if plugin_version:
966975
# Aggregate guids for older versions of files.
@@ -983,6 +992,7 @@ def add_guid(self, path, guid):
983992
path: Path associated with the GUID.
984993
guid: GUID for the asset at the path.
985994
"""
995+
path = posix_path(path)
986996
self._guids_by_path[path] = guid
987997
self._duplicate_guids_checker.add_guid_and_path(guid, path)
988998

@@ -1026,6 +1036,7 @@ def get_guid(self, path):
10261036
Raises:
10271037
MissingGuidsError: If the GUID isn't found.
10281038
"""
1039+
path = posix_path(path)
10291040
guid = self._guids_by_path.get(path)
10301041
if not guid:
10311042
raise MissingGuidsError([path])
@@ -1108,7 +1119,7 @@ def version_handler_filename(filename, field_value_list):
11081119
components.extend([VERSION_HANDLER_FIELD_SEPARATOR,
11091120
VERSION_HANDLER_FIELD_SEPARATOR.join(fields)])
11101121
components.append(extension)
1111-
return "".join(components)
1122+
return posix_path("".join(components))
11121123

11131124

11141125
class Asset(object):
@@ -1167,7 +1178,7 @@ def filename(self):
11671178
Returns:
11681179
Filename string.
11691180
"""
1170-
return self._filename
1181+
return posix_path(self._filename)
11711182

11721183
@property
11731184
def filename_absolute(self):
@@ -1176,7 +1187,7 @@ def filename_absolute(self):
11761187
Returns:
11771188
Filename string.
11781189
"""
1179-
return self._filename_absolute
1190+
return posix_path(self._filename_absolute)
11801191

11811192
@property
11821193
def filename_guid_lookup(self):
@@ -1185,7 +1196,7 @@ def filename_guid_lookup(self):
11851196
Returns:
11861197
Filename string.
11871198
"""
1188-
return self._filename_guid_lookup
1199+
return posix_path(self._filename_guid_lookup)
11891200

11901201
@property
11911202
def is_folder(self):
@@ -1239,7 +1250,7 @@ def disable_unsupported_platforms(importer_metadata, filename):
12391250
Returns:
12401251
Modified importer_metadata.
12411252
"""
1242-
filename = os.path.normpath(filename)
1253+
filename = posix_path(os.path.normpath(filename))
12431254
is_shared_library = SHARED_LIBRARY_PATH.search(filename)
12441255
if not is_shared_library:
12451256
return importer_metadata
@@ -1557,7 +1568,8 @@ def write(self, output_dir, guid, timestamp=-1):
15571568
# project.
15581569
with open(os.path.join(output_asset_dir, "pathname"), "wt") as (
15591570
pathname_file):
1560-
pathname_file.write(os.path.join(ASSETS_DIRECTORY, self.filename))
1571+
pathname_file.write(posix_path(os.path.join(ASSETS_DIRECTORY,
1572+
self.filename)))
15611573
return output_asset_dir
15621574

15631575
def write_upm(self, output_dir, guid, timestamp=-1):
@@ -2331,7 +2343,8 @@ def write_manifest(self, output_dir, assets):
23312343
os.makedirs(manifest_directory)
23322344
with open(manifest_absolute_path, "wt") as manifest_file:
23332345
manifest_file.write(
2334-
"%s\n" % "\n".join([os.path.join(ASSETS_DIRECTORY, asset.filename)
2346+
"%s\n" % "\n".join([posix_path(os.path.join(ASSETS_DIRECTORY,
2347+
asset.filename))
23352348
for asset in Asset.sorted_by_filename(assets)]))
23362349
# Retrieve a template manifest asset if it exists.
23372350
manifest_asset = [asset for asset in assets
@@ -3295,7 +3308,7 @@ def copy_files_to_dir(colon_separated_input_output_filenames,
32953308
copied_files = []
32963309
for additional_file in colon_separated_input_output_filenames:
32973310
additional_file_args = additional_file.split(":")
3298-
input_filename = additional_file_args[0]
3311+
input_filename = posix_path(additional_file_args[0])
32993312

33003313
# Get the output filename.
33013314
output_filename = input_filename
@@ -3306,11 +3319,11 @@ def copy_files_to_dir(colon_separated_input_output_filenames,
33063319
# Remove the drive or root directory from the output filename.
33073320
if os.path.normpath(output_filename).startswith(os.path.sep):
33083321
output_filename = output_filename[len(os.path.sep):]
3309-
output_filename = os.path.join(output_dir, output_filename)
3322+
output_filename = posix_path(os.path.join(output_dir, output_filename))
33103323

33113324
# Copy the file to the output directory.
33123325
copy_and_set_rwx(input_filename, output_filename)
3313-
copied_files.append(output_filename)
3326+
copied_files.append(posix_path(output_filename))
33143327
return copied_files
33153328

33163329

Diff for: source/ExportUnityPackage/export_unity_package_test.py

+20-15
Original file line numberDiff line numberDiff line change
@@ -1289,9 +1289,10 @@ def test_write_manifest(self):
12891289
manifest_asset.filename)
12901290
self.assertEqual("Foo/Bar/Test_version-1.2.3_manifest.txt",
12911291
manifest_asset.filename_guid_lookup)
1292-
manifest_absolute_path = os.path.join(
1293-
output_directory, "Foo/Bar/Test_version-1.2.3_manifest.txt")
1294-
self.assertEqual(manifest_absolute_path, manifest_asset.filename_absolute)
1292+
manifest_absolute_path = export_unity_package.posix_path(os.path.join(
1293+
output_directory, "Foo/Bar/Test_version-1.2.3_manifest.txt"))
1294+
self.assertEqual(manifest_absolute_path,
1295+
manifest_asset.filename_absolute)
12951296
self.assertFalse(manifest_asset.is_folder)
12961297
self.assertEqual(self.expected_manifest_metadata,
12971298
manifest_asset.importer_metadata)
@@ -1355,7 +1356,8 @@ def test_write_upm_manifest(self):
13551356
self.assertEqual("package.json", manifest_asset.filename)
13561357
self.assertEqual("com.company.test/package.json",
13571358
manifest_asset.filename_guid_lookup)
1358-
manifest_absolute_path = os.path.join(output_directory, "package.json")
1359+
manifest_absolute_path = export_unity_package.posix_path(
1360+
os.path.join(output_directory, "package.json"))
13591361
self.assertEqual(manifest_absolute_path, manifest_asset.filename_absolute)
13601362
self.assertFalse(manifest_asset.is_folder)
13611363
self.assertEqual(self.expected_upm_manifest_metadata,
@@ -2240,11 +2242,11 @@ def test_find_assets_in_multiple_directories(self):
22402242
[os.path.join(self.assets_dir, "Firebase"),
22412243
os.path.join(self.assets_dir, "PlayServicesResolver")])
22422244
self.assertCountEqual(
2243-
[os.path.join(
2244-
self.assets_dir, "Firebase/Plugins/Firebase.Analytics.dll"),
2245-
os.path.join(
2245+
[export_unity_package.posix_path(os.path.join(
2246+
self.assets_dir, "Firebase/Plugins/Firebase.Analytics.dll")),
2247+
export_unity_package.posix_path(os.path.join(
22462248
self.assets_dir,
2247-
"PlayServicesResolver/Editor/Google.VersionHandler.dll")],
2249+
"PlayServicesResolver/Editor/Google.VersionHandler.dll"))],
22482250
[asset.filename_absolute for asset in found_assets])
22492251

22502252
def test_find_assets_using_wildcard(self):
@@ -3245,6 +3247,10 @@ def setUp(self):
32453247
super(FileOperationsTest, self).setUp()
32463248
self.assets_dir = os.path.join(TEST_DATA_PATH, "Assets")
32473249
self.temp_dir = os.path.join(FLAGS.test_tmpdir, "copy_temp")
3250+
self.expected_mode = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
3251+
if platform.system() == 'Windows':
3252+
# Windows doesn't support the executable mode so ignore it in tests.
3253+
self.expected_mode = self.expected_mode & ~stat.S_IXUSR
32483254
os.makedirs(self.temp_dir)
32493255

32503256
def tearDown(self):
@@ -3264,9 +3270,8 @@ def test_copy_and_set_rwx(self):
32643270
export_unity_package.copy_and_set_rwx(source_path, target_path)
32653271
self.assertTrue(os.path.exists(target_path))
32663272
self.assertTrue(filecmp.cmp(source_path, target_path))
3267-
self.assertEqual(
3268-
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR,
3269-
os.stat(target_path).st_mode & stat.S_IRWXU)
3273+
self.assertEqual(self.expected_mode,
3274+
os.stat(target_path).st_mode & stat.S_IRWXU)
32703275

32713276
def test_copy_and_set_rwx_new_dir(self):
32723277
"""Copy a file into a non-existent directory."""
@@ -3281,9 +3286,8 @@ def test_copy_and_set_rwx_new_dir(self):
32813286
export_unity_package.copy_and_set_rwx(source_path, target_path)
32823287
self.assertTrue(os.path.exists(target_path))
32833288
self.assertTrue(filecmp.cmp(source_path, target_path))
3284-
self.assertEqual(
3285-
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR,
3286-
os.stat(target_path).st_mode & stat.S_IRWXU)
3289+
self.assertEqual(self.expected_mode,
3290+
os.stat(target_path).st_mode & stat.S_IRWXU)
32873291

32883292
def test_copy_files_to_dir(self):
32893293
"""Test copying files into a directory using a variety of target paths."""
@@ -3324,11 +3328,12 @@ def test_copy_dir_to_dir(self):
33243328
cmp_result = filecmp.dircmp(source_path, target_path)
33253329
self.assertFalse(cmp_result.left_only or cmp_result.right_only or
33263330
cmp_result.diff_files)
3331+
# NOTE: Folders have the executable bit set on Windows.
33273332
self.assertEqual(
33283333
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR,
33293334
os.stat(os.path.join(target_path, "Editor")).st_mode & stat.S_IRWXU)
33303335
self.assertEqual(
3331-
stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR,
3336+
self.expected_mode,
33323337
(os.stat(os.path.join(target_path, "Editor.meta")).st_mode &
33333338
stat.S_IRWXU))
33343339

0 commit comments

Comments
 (0)