1919// A mapping of item IDs to filenames is maintained in the download directory.
2020// This mapping efficiently checks whether an item has already been downloaded.
2121// If an item already exists, it will skip that item.
22+ // To delete and re-downloaded an item, remove its entry from the plist.
2223
2324import Foundation
2425
@@ -31,7 +32,7 @@ struct SampleDependency: Decodable {
3132}
3233
3334/// A Portal Item and its data URL.
34- struct PortalItem {
35+ struct PortalItem : Hashable {
3536 static let arcGISOnlinePortalURL = URL ( string: " https://www.arcgis.com " ) !
3637
3738 /// The identifier of the item.
@@ -207,7 +208,7 @@ if !FileManager.default.fileExists(atPath: downloadDirectoryURL.path) {
207208}
208209
209210/// Portal Items created from iterating through all metadata's "offline\_data".
210- let portalItems : [ PortalItem ] = {
211+ let portalItems : Set < PortalItem > = {
211212 do {
212213 // Finds all subdirectories under the root Samples directory.
213214 let sampleSubDirectories = try FileManager . default
@@ -218,7 +219,7 @@ let portalItems: [PortalItem] = {
218219 // Omit the decoding errors from samples that don't have dependencies.
219220 let sampleDependencies = sampleJSONs
220221 . compactMap { try ? parseJSON ( at: $0) }
221- return sampleDependencies. flatMap ( \. offlineData)
222+ return Set ( sampleDependencies. lazy . flatMap ( \. offlineData) )
222223 } catch {
223224 print ( " error: Error decoding Samples dependencies: \( error. localizedDescription) " )
224225 exit ( 1 )
@@ -244,33 +245,39 @@ var downloadedItems = previousDownloadedItems
244245// Asynchronously downloads portal items.
245246let dispatchGroup = DispatchGroup ( )
246247
247- portalItems. forEach { portalItem in
248+ for portalItem in portalItems {
249+ // Checks to see if an item is already downloaded.
250+ guard downloadedItems [ portalItem. identifier] == nil else {
251+ print ( " note: Item already downloaded: \( portalItem. identifier) " )
252+ continue
253+ }
254+
248255 let destinationURL = downloadDirectoryURL. appendingPathComponent ( portalItem. identifier, isDirectory: true )
249- // Checks if a directory exists or not, to see if an item is already downloaded.
250- if FileManager . default. fileExists ( atPath: destinationURL. path) {
251- print ( " info: Item \( portalItem. identifier) has already been downloaded. " )
252- } else {
253- do {
254- // Creates an enclosing directory with portal item ID as its name.
255- try FileManager . default. createDirectory ( at: destinationURL, withIntermediateDirectories: false )
256- } catch {
257- print ( " error: Error creating download directory: \( error. localizedDescription) . " )
256+
257+ // Deletes the directory when the item is not in the plist.
258+ try ? FileManager . default. removeItem ( at: destinationURL)
259+
260+ do {
261+ // Creates an enclosing directory with portal item ID as its name.
262+ try FileManager . default. createDirectory ( at: destinationURL, withIntermediateDirectories: false )
263+ } catch {
264+ print ( " error: Error creating download directory: \( error. localizedDescription) " )
265+ exit ( 1 )
266+ }
267+
268+ print ( " note: Downloading item \( portalItem. identifier) " )
269+ fflush ( stdout)
270+ dispatchGroup. enter ( )
271+ downloadFile ( at: portalItem. dataURL, to: destinationURL) { result in
272+ switch result {
273+ case . success( let url) :
274+ downloadedItems [ portalItem. identifier] = url. lastPathComponent
275+ dispatchGroup. leave ( )
276+ case . failure( let error) :
277+ print ( " error: Error downloading item \( portalItem. identifier) : \( error. localizedDescription) " )
278+ URLSession . shared. invalidateAndCancel ( )
258279 exit ( 1 )
259280 }
260- print ( " info: Downloading item \( portalItem. identifier) " )
261- fflush ( stdout)
262- dispatchGroup. enter ( )
263- downloadFile ( at: portalItem. dataURL, to: destinationURL) { result in
264- switch result {
265- case . success( let url) :
266- downloadedItems [ portalItem. identifier] = url. lastPathComponent
267- dispatchGroup. leave ( )
268- case . failure( let error) :
269- print ( " error: Error downloading item \( portalItem. identifier) : \( error. localizedDescription) " )
270- URLSession . shared. invalidateAndCancel ( )
271- exit ( 1 )
272- }
273- }
274281 }
275282}
276283dispatchGroup. wait ( )
0 commit comments