@@ -160,8 +160,8 @@ class DevFSStringContent extends DevFSByteContent {
160
160
abstract class DevFSOperations {
161
161
Future <Uri > create (String fsName);
162
162
Future <dynamic > destroy (String fsName);
163
- Future <dynamic > writeFile (String fsName, String devicePath , DevFSContent content);
164
- Future <dynamic > deleteFile (String fsName, String devicePath );
163
+ Future <dynamic > writeFile (String fsName, Uri deviceUri , DevFSContent content);
164
+ Future <dynamic > deleteFile (String fsName, Uri deviceUri );
165
165
}
166
166
167
167
/// An implementation of [DevFSOperations] that speaks to the
@@ -186,7 +186,7 @@ class ServiceProtocolDevFSOperations implements DevFSOperations {
186
186
}
187
187
188
188
@override
189
- Future <dynamic > writeFile (String fsName, String devicePath , DevFSContent content) async {
189
+ Future <dynamic > writeFile (String fsName, Uri deviceUri , DevFSContent content) async {
190
190
List <int > bytes;
191
191
try {
192
192
bytes = await content.contentsAsBytes ();
@@ -199,17 +199,18 @@ class ServiceProtocolDevFSOperations implements DevFSOperations {
199
199
'_writeDevFSFile' ,
200
200
params: < String , dynamic > {
201
201
'fsName' : fsName,
202
- 'path' : devicePath,
202
+ // TODO(goderbauer): transfer real Uri (instead of file path) when remote end supports it
203
+ 'path' : deviceUri.toFilePath (windows: false ),
203
204
'fileContents' : fileContents
204
205
},
205
206
);
206
207
} catch (error) {
207
- printTrace ('DevFS: Failed to write $devicePath : $error ' );
208
+ printTrace ('DevFS: Failed to write $deviceUri : $error ' );
208
209
}
209
210
}
210
211
211
212
@override
212
- Future <dynamic > deleteFile (String fsName, String devicePath ) async {
213
+ Future <dynamic > deleteFile (String fsName, Uri deviceUri ) async {
213
214
// TODO(johnmccutchan): Add file deletion to the devFS protocol.
214
215
}
215
216
}
@@ -225,18 +226,18 @@ class _DevFSHttpWriter {
225
226
static const int kMaxRetries = 3 ;
226
227
227
228
int _inFlight = 0 ;
228
- Map <String , DevFSContent > _outstanding;
229
+ Map <Uri , DevFSContent > _outstanding;
229
230
Completer <Null > _completer;
230
231
HttpClient _client;
231
232
int _done;
232
233
int _max;
233
234
234
- Future <Null > write (Map <String , DevFSContent > entries,
235
+ Future <Null > write (Map <Uri , DevFSContent > entries,
235
236
{DevFSProgressReporter progressReporter}) async {
236
237
_client = new HttpClient ();
237
238
_client.maxConnectionsPerHost = kMaxInFlight;
238
239
_completer = new Completer <Null >();
239
- _outstanding = new Map <String , DevFSContent >.from (entries);
240
+ _outstanding = new Map <Uri , DevFSContent >.from (entries);
240
241
_done = 0 ;
241
242
_max = _outstanding.length;
242
243
_scheduleWrites (progressReporter);
@@ -250,15 +251,15 @@ class _DevFSHttpWriter {
250
251
// Finished.
251
252
break ;
252
253
}
253
- String devicePath = _outstanding.keys.first;
254
- DevFSContent content = _outstanding.remove (devicePath );
255
- _scheduleWrite (devicePath , content, progressReporter);
254
+ Uri deviceUri = _outstanding.keys.first;
255
+ DevFSContent content = _outstanding.remove (deviceUri );
256
+ _scheduleWrite (deviceUri , content, progressReporter);
256
257
_inFlight++ ;
257
258
}
258
259
}
259
260
260
261
Future <Null > _scheduleWrite (
261
- String devicePath ,
262
+ Uri deviceUri ,
262
263
DevFSContent content,
263
264
DevFSProgressReporter progressReporter, [
264
265
int retry = 0 ,
@@ -267,19 +268,20 @@ class _DevFSHttpWriter {
267
268
HttpClientRequest request = await _client.putUrl (httpAddress);
268
269
request.headers.removeAll (HttpHeaders .ACCEPT_ENCODING );
269
270
request.headers.add ('dev_fs_name' , fsName);
271
+ // TODO(goderbauer): transfer real Uri (instead of file path) when remote end supports it
270
272
request.headers.add ('dev_fs_path_b64' ,
271
- BASE64 .encode (UTF8 .encode (devicePath )));
273
+ BASE64 .encode (UTF8 .encode (deviceUri. toFilePath (windows : false ) )));
272
274
Stream <List <int >> contents = content.contentsAsCompressedStream ();
273
275
await request.addStream (contents);
274
276
HttpClientResponse response = await request.close ();
275
277
await response.drain <Null >();
276
278
} catch (e) {
277
279
if (retry < kMaxRetries) {
278
- printTrace ('Retrying writing "$devicePath " to DevFS due to error: $e ' );
279
- _scheduleWrite (devicePath , content, progressReporter, retry + 1 );
280
+ printTrace ('Retrying writing "$deviceUri " to DevFS due to error: $e ' );
281
+ _scheduleWrite (deviceUri , content, progressReporter, retry + 1 );
280
282
return ;
281
283
} else {
282
- printError ('Error writing "$devicePath " to DevFS: $e ' );
284
+ printError ('Error writing "$deviceUri " to DevFS: $e ' );
283
285
}
284
286
}
285
287
if (progressReporter != null ) {
@@ -324,7 +326,7 @@ class DevFS {
324
326
final String fsName;
325
327
final Directory rootDirectory;
326
328
String _packagesFilePath;
327
- final Map <String , DevFSContent > _entries = < String , DevFSContent > {};
329
+ final Map <Uri , DevFSContent > _entries = < Uri , DevFSContent > {};
328
330
final Set <String > assetPathsToEvict = new Set <String >();
329
331
330
332
final List <Future <Map <String , dynamic >>> _pendingOperations =
@@ -373,17 +375,17 @@ class DevFS {
373
375
374
376
// Handle deletions.
375
377
printTrace ('Scanning for deleted files' );
376
- String assetBuildDirPrefix = getAssetBuildDirectory () + fs.path.separator ;
377
- final List <String > toRemove = new List <String >();
378
- _entries.forEach ((String devicePath , DevFSContent content) {
378
+ String assetBuildDirPrefix = _asUriPath ( getAssetBuildDirectory ()) ;
379
+ final List <Uri > toRemove = new List <Uri >();
380
+ _entries.forEach ((Uri deviceUri , DevFSContent content) {
379
381
if (! content._exists) {
380
382
Future <Map <String , dynamic >> operation =
381
- _operations.deleteFile (fsName, devicePath );
383
+ _operations.deleteFile (fsName, deviceUri );
382
384
if (operation != null )
383
385
_pendingOperations.add (operation);
384
- toRemove.add (devicePath );
385
- if (devicePath .startsWith (assetBuildDirPrefix)) {
386
- String archivePath = devicePath .substring (assetBuildDirPrefix.length);
386
+ toRemove.add (deviceUri );
387
+ if (deviceUri.path .startsWith (assetBuildDirPrefix)) {
388
+ String archivePath = deviceUri.path .substring (assetBuildDirPrefix.length);
387
389
assetPathsToEvict.add (archivePath);
388
390
}
389
391
}
@@ -397,13 +399,13 @@ class DevFS {
397
399
398
400
// Update modified files
399
401
int numBytes = 0 ;
400
- Map <String , DevFSContent > dirtyEntries = < String , DevFSContent > {};
401
- _entries.forEach ((String devicePath , DevFSContent content) {
402
+ Map <Uri , DevFSContent > dirtyEntries = < Uri , DevFSContent > {};
403
+ _entries.forEach ((Uri deviceUri , DevFSContent content) {
402
404
String archivePath;
403
- if (devicePath .startsWith (assetBuildDirPrefix))
404
- archivePath = devicePath .substring (assetBuildDirPrefix.length);
405
+ if (deviceUri.path .startsWith (assetBuildDirPrefix))
406
+ archivePath = deviceUri.path .substring (assetBuildDirPrefix.length);
405
407
if (content.isModified || (bundleDirty && archivePath != null )) {
406
- dirtyEntries[devicePath ] = content;
408
+ dirtyEntries[deviceUri ] = content;
407
409
numBytes += content.size;
408
410
if (archivePath != null )
409
411
assetPathsToEvict.add (archivePath);
@@ -420,9 +422,9 @@ class DevFS {
420
422
}
421
423
} else {
422
424
// Make service protocol requests for each.
423
- dirtyEntries.forEach ((String devicePath , DevFSContent content) {
425
+ dirtyEntries.forEach ((Uri deviceUri , DevFSContent content) {
424
426
Future <Map <String , dynamic >> operation =
425
- _operations.writeFile (fsName, devicePath , content);
427
+ _operations.writeFile (fsName, deviceUri , content);
426
428
if (operation != null )
427
429
_pendingOperations.add (operation);
428
430
});
@@ -446,41 +448,44 @@ class DevFS {
446
448
return numBytes;
447
449
}
448
450
449
- void _scanFile (String devicePath , FileSystemEntity file) {
450
- DevFSContent content = _entries.putIfAbsent (devicePath , () => new DevFSFileContent (file));
451
+ void _scanFile (Uri deviceUri , FileSystemEntity file) {
452
+ DevFSContent content = _entries.putIfAbsent (deviceUri , () => new DevFSFileContent (file));
451
453
content._exists = true ;
452
454
}
453
455
454
456
void _scanBundleEntry (String archivePath, DevFSContent content, bool bundleDirty) {
455
457
// We write the assets into the AssetBundle working dir so that they
456
458
// are in the same location in DevFS and the iOS simulator.
457
- final String devicePath = fs.path.join (getAssetBuildDirectory (), archivePath);
459
+ final Uri deviceUri = fs.path.toUri (fs.path. join (getAssetBuildDirectory (), archivePath) );
458
460
459
- _entries[devicePath ] = content;
461
+ _entries[deviceUri ] = content;
460
462
content._exists = true ;
461
463
}
462
464
463
- bool _shouldIgnore (String devicePath ) {
464
- List <String > ignoredPrefixes = < String > ['android' + fs.path.separator ,
465
- getBuildDirectory (),
466
- 'ios' + fs.path.separator ,
467
- '.pub' + fs.path.separator ];
468
- for (String ignoredPrefix in ignoredPrefixes ) {
469
- if (devicePath. startsWith (ignoredPrefix ))
465
+ bool _shouldIgnore (Uri deviceUri ) {
466
+ List <String > ignoredUriPrefixes = < String > ['android/' ,
467
+ _asUriPath ( getBuildDirectory () ),
468
+ 'ios/' ,
469
+ '.pub/' ];
470
+ for (String ignoredUriPrefix in ignoredUriPrefixes ) {
471
+ if (deviceUri.path. startsWith (ignoredUriPrefix ))
470
472
return true ;
471
473
}
472
474
return false ;
473
475
}
474
476
475
477
Future <bool > _scanDirectory (Directory directory,
476
- {String directoryNameOnDevice ,
478
+ {Uri directoryUriOnDevice ,
477
479
bool recursive: false ,
478
480
bool ignoreDotFiles: true ,
479
481
Set <String > fileFilter}) async {
480
- if (directoryNameOnDevice == null ) {
481
- directoryNameOnDevice = fs.path.relative (directory.path, from: rootDirectory.path);
482
- if (directoryNameOnDevice == '.' )
483
- directoryNameOnDevice = '' ;
482
+ if (directoryUriOnDevice == null ) {
483
+ String relativeRootPath = fs.path.relative (directory.path, from: rootDirectory.path);
484
+ if (relativeRootPath == '.' ) {
485
+ directoryUriOnDevice = new Uri ();
486
+ } else {
487
+ directoryUriOnDevice = fs.path.toUri (relativeRootPath);
488
+ }
484
489
}
485
490
try {
486
491
Stream <FileSystemEntity > files =
@@ -506,17 +511,17 @@ class DevFS {
506
511
}
507
512
final String relativePath =
508
513
fs.path.relative (file.path, from: directory.path);
509
- final String devicePath = fs.path.join (directoryNameOnDevice, relativePath);
514
+ final Uri deviceUri = directoryUriOnDevice. resolveUri ( fs.path.toUri ( relativePath) );
510
515
if ((fileFilter != null ) && ! fileFilter.contains (file.absolute.path)) {
511
516
// Skip files that are not included in the filter.
512
517
continue ;
513
518
}
514
- if (ignoreDotFiles && devicePath .startsWith ('.' )) {
519
+ if (ignoreDotFiles && deviceUri.path .startsWith ('.' )) {
515
520
// Skip directories that start with a dot.
516
521
continue ;
517
522
}
518
- if (! _shouldIgnore (devicePath ))
519
- _scanFile (devicePath , file);
523
+ if (! _shouldIgnore (deviceUri ))
524
+ _scanFile (deviceUri , file);
520
525
}
521
526
} catch (e) {
522
527
// Ignore directory and error.
@@ -531,34 +536,38 @@ class DevFS {
531
536
532
537
for (String packageName in packageMap.map.keys) {
533
538
Uri packageUri = packageMap.map[packageName];
534
- String packagePath = fs.path. fromUri (packageUri );
539
+ String packagePath = packageUri. toFilePath ( );
535
540
Directory packageDirectory = fs.directory (packageUri);
536
- String directoryNameOnDevice = fs.path.join ('packages' , packageName);
541
+ Uri directoryUriOnDevice = fs.path.toUri (fs.path. join ('packages' , packageName) + fs.path.separator );
537
542
bool packageExists;
538
543
539
544
if (fs.path.isWithin (rootDirectory.path, packagePath)) {
540
545
// We already scanned everything under the root directory.
541
546
packageExists = packageDirectory.existsSync ();
542
- directoryNameOnDevice = fs.path.relative (packagePath, from: rootDirectory.path);
547
+ directoryUriOnDevice = fs.path.toUri (
548
+ fs.path.relative (packagePath, from: rootDirectory.path) + fs.path.separator
549
+ );
543
550
} else {
544
551
packageExists =
545
552
await _scanDirectory (packageDirectory,
546
- directoryNameOnDevice : directoryNameOnDevice ,
553
+ directoryUriOnDevice : directoryUriOnDevice ,
547
554
recursive: true ,
548
555
fileFilter: fileFilter);
549
556
}
550
557
if (packageExists) {
551
558
sb ?? = new StringBuffer ();
552
- sb.writeln ('$packageName :$directoryNameOnDevice ' );
559
+ sb.writeln ('$packageName :$directoryUriOnDevice ' );
553
560
}
554
561
}
555
562
if (sb != null ) {
556
- DevFSContent content = _entries['.packages' ];
563
+ DevFSContent content = _entries[fs.path. toUri ( '.packages' ) ];
557
564
if (content is DevFSStringContent && content.string == sb.toString ()) {
558
565
content._exists = true ;
559
566
return ;
560
567
}
561
- _entries['.packages' ] = new DevFSStringContent (sb.toString ());
568
+ _entries[fs.path. toUri ( '.packages' ) ] = new DevFSStringContent (sb.toString ());
562
569
}
563
570
}
564
571
}
572
+ /// Converts a platform-specific file path to a platform-independent Uri path.
573
+ String _asUriPath (String filePath) => fs.path.toUri (filePath).path + '/' ;
0 commit comments