Browse Source

Make fs.stat support asar package

Cheng Zhao 10 years ago
parent
commit
9b755620d3

+ 1 - 0
atom.gyp

@@ -39,6 +39,7 @@
       'atom/common/api/lib/screen.coffee',
       'atom/common/api/lib/shell.coffee',
       'atom/common/lib/init.coffee',
+      'atom/common/lib/asar.coffee',
       'atom/renderer/lib/chrome-api.coffee',
       'atom/renderer/lib/init.coffee',
       'atom/renderer/lib/inspector.coffee',

+ 1 - 1
atom/browser/lib/init.coffee

@@ -80,7 +80,7 @@ setImmediate ->
   # Set application's desktop name.
   if packageJson.desktopName?
     app.setDesktopName packageJson.desktopName
-  else 
+  else
     app.setDesktopName '#{app.getName()}.desktop'
 
   # Load the chrome extension support.

+ 3 - 3
atom/common/api/atom_api_asar.cc

@@ -21,7 +21,7 @@ class Archive : public mate::Wrappable {
     static asar::ArchiveFactory archive_factory;
     scoped_refptr<asar::Archive> archive = archive_factory.GetOrCreate(path);
     if (!archive)
-      return args->ThrowError("Invalid asar archive");
+      return v8::False(args->isolate());
     return (new Archive(archive))->GetWrapper(args->isolate());
   }
 
@@ -34,7 +34,7 @@ class Archive : public mate::Wrappable {
                                     const base::FilePath& path) {
     asar::Archive::FileInfo info;
     if (!archive_->GetFileInfo(path, &info))
-      return args->ThrowError("Can not find file");
+      return v8::False(args->isolate());
     mate::Dictionary dict(args->isolate(), v8::Object::New(args->isolate()));
     dict.Set("size", info.size);
     dict.Set("offset", info.offset);
@@ -46,7 +46,7 @@ class Archive : public mate::Wrappable {
                              const base::FilePath& path) {
     asar::Archive::Stats stats;
     if (!archive_->Stat(path, &stats))
-      return args->ThrowError("Can not find file");
+      return v8::False(args->isolate());
     mate::Dictionary dict(args->isolate(), v8::Object::New(args->isolate()));
     dict.Set("size", stats.size);
     dict.Set("offset", stats.offset);

+ 64 - 0
atom/common/lib/asar.coffee

@@ -0,0 +1,64 @@
+asar = process.atomBinding 'asar'
+fs = require 'fs'
+path = require 'path'
+
+# Separate asar package's path from full path.
+splitPath = (p) ->
+  components = p.split path.sep
+  for c, i in components by -1
+    if path.extname(c) is '.asar'
+      asarPath = components.slice(0, i + 1).join path.sep
+      filePath = components.slice(i + 1).join path.sep
+      return [true, asarPath, filePath]
+  return [false, p]
+
+# Convert asar archive's Stats object to fs's Stats object.
+asarStatsToFsStats = (stats) ->
+  {
+    size: stats.size
+    isFile: -> stats.isFile
+    isDirectory: -> stats.isDirectory
+    isSymbolicLink: -> stats.isLink
+    isBlockDevice: -> false
+    isCharacterDevice: -> false
+    isFIFO: -> false
+    isSocket: -> false
+  }
+
+# Override fs APIs.
+statSync = fs.statSync
+fs.statSync = (p) ->
+  [isAsar, asarPath, filePath] = splitPath p
+  return statSync p unless isAsar
+
+  archive = asar.createArchive asarPath
+  throw new Error("Invalid package #{asarPath}") unless archive
+
+  stats = archive.stat filePath
+  throw new Error("#{filePath} not found in #{asarPath}") unless stats
+
+  asarStatsToFsStats stats
+
+stat = fs.stat
+fs.stat = (p, callback) ->
+  [isAsar, asarPath, filePath] = splitPath p
+  return stat p, callback unless isAsar
+
+  archive = asar.createArchive asarPath
+  return callback throw new Error("Invalid package #{asarPath}") unless archive
+
+  stats = asar.createArchive(asarPath).stat filePath
+  return callback new Error("#{filePath} not found in #{asarPath}") unless stats
+
+  callback undefined, asarStatsToFsStats stats
+
+statSyncNoException = fs.statSyncNoException
+fs.statSyncNoException = (p) ->
+  [isAsar, asarPath, filePath] = splitPath p
+  return statSyncNoException p unless isAsar
+
+  archive = asar.createArchive asarPath
+  return false unless archive
+  stats = asar.createArchive(asarPath).stat filePath
+  return false unless stats
+  asarStatsToFsStats stats

+ 3 - 0
atom/common/lib/init.coffee

@@ -33,3 +33,6 @@ global.clearImmediate = timers.clearImmediate
 if process.type is 'browser'
   global.setTimeout = wrapWithActivateUvLoop timers.setTimeout
   global.setInterval = wrapWithActivateUvLoop timers.setInterval
+
+# Add support for asar packages.
+require './asar'