--- /dev/null
+var common = require('./common');
+var fs = require('fs');
+
+// Recursively removes 'dir'
+// Adapted from https://github.com/ryanmcgrath/wrench-js
+//
+// Copyright (c) 2010 Ryan McGrath
+// Copyright (c) 2012 Artur Adib
+//
+// Licensed under the MIT License
+// http://www.opensource.org/licenses/mit-license.php
+function rmdirSyncRecursive(dir, force) {
+ var files;
+
+ files = fs.readdirSync(dir);
+
+ // Loop through and delete everything in the sub-tree after checking it
+ for(var i = 0; i < files.length; i++) {
+ var file = dir + "/" + files[i],
+ currFile = fs.lstatSync(file);
+
+ if(currFile.isDirectory()) { // Recursive function back to the beginning
+ rmdirSyncRecursive(file, force);
+ }
+
+ else if(currFile.isSymbolicLink()) { // Unlink symlinks
+ if (force || isWriteable(file)) {
+ try {
+ common.unlinkSync(file);
+ } catch (e) {
+ common.error('could not remove file (code '+e.code+'): ' + file, true);
+ }
+ }
+ }
+
+ else // Assume it's a file - perhaps a try/catch belongs here?
+ if (force || isWriteable(file)) {
+ try {
+ common.unlinkSync(file);
+ } catch (e) {
+ common.error('could not remove file (code '+e.code+'): ' + file, true);
+ }
+ }
+ }
+
+ // Now that we know everything in the sub-tree has been deleted, we can delete the main directory.
+ // Huzzah for the shopkeep.
+
+ var result;
+ try {
+ result = fs.rmdirSync(dir);
+ } catch(e) {
+ common.error('could not remove directory (code '+e.code+'): ' + dir, true);
+ }
+
+ return result;
+} // rmdirSyncRecursive
+
+// Hack to determine if file has write permissions for current user
+// Avoids having to check user, group, etc, but it's probably slow
+function isWriteable(file) {
+ var writePermission = true;
+ try {
+ var __fd = fs.openSync(file, 'a');
+ fs.closeSync(__fd);
+ } catch(e) {
+ writePermission = false;
+ }
+
+ return writePermission;
+}
+
+//@
+//@ ### rm([options ,] file [, file ...])
+//@ ### rm([options ,] file_array)
+//@ Available options:
+//@
+//@ + `-f`: force
+//@ + `-r, -R`: recursive
+//@
+//@ Examples:
+//@
+//@ ```javascript
+//@ rm('-rf', '/tmp/*');
+//@ rm('some_file.txt', 'another_file.txt');
+//@ rm(['some_file.txt', 'another_file.txt']); // same as above
+//@ ```
+//@
+//@ Removes files. The wildcard `*` is accepted.
+function _rm(options, files) {
+ options = common.parseOptions(options, {
+ 'f': 'force',
+ 'r': 'recursive',
+ 'R': 'recursive'
+ });
+ if (!files)
+ common.error('no paths given');
+
+ if (typeof files === 'string')
+ files = [].slice.call(arguments, 1);
+ // if it's array leave it as it is
+
+ files = common.expand(files);
+
+ files.forEach(function(file) {
+ if (!fs.existsSync(file)) {
+ // Path does not exist, no force flag given
+ if (!options.force)
+ common.error('no such file or directory: '+file, true);
+
+ return; // skip file
+ }
+
+ // If here, path exists
+
+ var stats = fs.lstatSync(file);
+ if (stats.isFile() || stats.isSymbolicLink()) {
+
+ // Do not check for file writing permissions
+ if (options.force) {
+ common.unlinkSync(file);
+ return;
+ }
+
+ if (isWriteable(file))
+ common.unlinkSync(file);
+ else
+ common.error('permission denied: '+file, true);
+
+ return;
+ } // simple file
+
+ // Path is an existing directory, but no -r flag given
+ if (stats.isDirectory() && !options.recursive) {
+ common.error('path is a directory', true);
+ return; // skip path
+ }
+
+ // Recursively remove existing directory
+ if (stats.isDirectory() && options.recursive) {
+ rmdirSyncRecursive(file, options.force);
+ }
+ }); // forEach(file)
+} // rm
+module.exports = _rm;