Module: Commands
- Defined in:
- lib/droxi/commands.rb
Overview
Module containing definitions for client commands.
Defined Under Namespace
Classes: Command
Constant Summary collapse
- UsageError =
Exception indicating that a client command was given the wrong number of arguments.
Class.new(ArgumentError)
- CAT =
Print the contents of remote files.
Command.new( 'cat REMOTE_FILE...', 'Print the concatenated contents of remote files.', lambda do |client, state, args| extract_flags(CAT.usage, args, {}) state.(args).each do |path| if path.is_a?(GlobError) warn "cat: #{path}: no such file or directory" else puts client.get_file(path) end end end )
- CD =
Change the remote working directory.
Command.new( 'cd [REMOTE_DIR]', "Change the remote working directory. With no arguments, changes to the \ Dropbox root. With a remote directory name as the argument, changes to \ that directory. With - as the argument, changes to the previous working \ directory.", lambda do |_client, state, args| extract_flags(CD.usage, args, {}) case when args.empty? then state.pwd = '/' when args.first == '-' then state.pwd = state.oldpwd else path = state.resolve_path(args.first) if state.directory?(path) state.pwd = path else warn "cd: #{args.first}: no such directory" end end end )
- CP =
Copy remote files.
Command.new( 'cp [-f] REMOTE_FILE... REMOTE_FILE', "When given two arguments, copies the remote file or folder at the first \ path to the second path. When given more than two arguments or when the \ final argument is a directory, copies each remote file or folder into \ that directory. Will refuse to overwrite existing files unless invoked \ with the -f option.", lambda do |client, state, args| cp_mv(client, state, args, 'cp', CP.usage) end )
- DEBUG =
Execute arbitrary code.
Command.new( 'debug STRING...', "Evaluates the given string as Ruby code and prints the result. Won't \ work unless the program was invoked with the --debug flag.", # rubocop:disable Lint/UnusedBlockArgument, Lint/Eval lambda do |client, state, args| if ARGV.include?('--debug') begin p eval(args.join(' ')) # rubocop:enable Lint/UnusedBlockArgument, Lint/Eval rescue SyntaxError => error warn error rescue => error warn error.inspect end else warn 'debug: not enabled.' end end )
- EXIT =
Terminate the session.
Command.new( 'exit', 'Exit the program.', lambda do |_client, state, args| extract_flags(EXIT.usage, args, {}) state.exit_requested = true end )
- FORGET =
Clear the cache.
Command.new( 'forget [REMOTE_DIR]...', "Clear the client-side cache of remote filesystem metadata. With no \ arguments, clear the entire cache. If given directories as arguments, \ (recursively) clear the cache of those directories only.", lambda do |_client, state, args| extract_flags(FORGET.usage, args, {}) if args.empty? state.cache.clear else args.each do |arg| state.forget_contents(arg) { |line| warn line } end end end )
- GET =
Download remote files.
Command.new( 'get [-E] [-f] REMOTE_FILE...', "Download each specified remote file to a file of the same name in the \ local working directory. Will refuse to overwrite existing files unless \ invoked with the -f option. If the -E option is given, remove each \ remote file after successful download.", lambda do |client, state, args| flags = extract_flags(GET.usage, args, '-E' => 0, '-f' => 0) state.(args).each do |path| if path.is_a?(GlobError) warn "get: #{path}: no such file or directory" else basename = File.basename(path) try_and_handle(DropboxError) do if flags.include?('-f') || !File.exist?(basename) contents = client.get_file(path) IO.write(basename, contents, mode: 'wb') if flags.include?('-E') client.file_delete(path) state.cache.remove(path) end puts "#{basename} <- #{path}" else warn "get: #{basename}: local file already exists" end end end end end )
- HELP =
List commands, or print information about a specific command.
Command.new( 'help [COMMAND]', "Print usage and help information about a command. If no command is \ given, print a list of commands instead.", lambda do |_client, _state, args| extract_flags(HELP.usage, args, {}) if args.empty? puts 'Type "help <command>" for more info about a command:' Text.table(NAMES).each { |line| puts line } else cmd_name = args.first if NAMES.include?(cmd_name) cmd = const_get(cmd_name.upcase.to_s) puts cmd.usage Text.wrap(cmd.description).each { |line| puts line } else warn "help: #{cmd_name}: no such command" end end end )
- HISTORY =
Get remote file revisions.
Command.new( 'history REMOTE_FILE', "Print a list of revisions for a remote file. The file can be restored to \ a previous revision using the 'restore' command and a revision ID given \ by this command.", lambda do |client, state, args| extract_flags(HISTORY.usage, args, {}) path = state.resolve_path(args.first) if !state.(path) || state.directory?(path) warn "history: #{args.first}: no such file" else try_and_handle(DropboxError) do client.revisions(path).each do |rev| size = rev['size'].sub(/ (.)B/, '\1').sub(' bytes', '').rjust(7) mtime = Time.parse(rev['modified']) current_year = (mtime.year == Time.now.year) format_str = current_year ? '%b %e %H:%M' : '%b %e %Y' puts "#{size} #{mtime.strftime(format_str)} #{rev['rev']}" end end end end )
- LCD =
Change the local working directory.
Command.new( 'lcd [LOCAL_DIR]', "Change the local working directory. With no arguments, changes to the \ home directory. With a local directory name as the argument, changes to \ that directory. With - as the argument, changes to the previous working \ directory.", lambda do |_client, state, args| extract_flags(LCD.usage, args, {}) path = case when args.empty? then File.('~') when args.first == '-' then state.local_oldpwd else begin File.(args.first) rescue ArgumentError args.first end end if Dir.exist?(path) state.local_oldpwd = Dir.pwd Dir.chdir(path) else warn "lcd: #{args.first}: no such directory" end end )
- LS =
List remote files.
Command.new( 'ls [-l] [REMOTE_FILE]...', "List information about remote files. With no arguments, list the \ contents of the working directory. When given remote directories as \ arguments, list the contents of the directories. When given remote files \ as arguments, list the files. If the -l option is given, display \ information about the files.", lambda do |_client, state, args| long = extract_flags(LS.usage, args, '-l' => 0).include?('-l') files, dirs = [], [] state.(args, true).each do |path| if path.is_a?(GlobError) warn "ls: #{path}: no such file or directory" else type = state.directory?(path) ? dirs : files type << path end end dirs << state.pwd if args.empty? # First list files. list(state, files, files, long) { |line| puts line } puts unless dirs.empty? || files.empty? # Then list directory contents. dirs.each_with_index do |dir, i| puts "#{dir}:" if dirs.size + files.size > 1 contents = state.contents(dir) names = contents.map { |path| File.basename(path) } list(state, contents, names, long) { |line| puts line } puts if i < dirs.size - 1 end end )
- MEDIA =
Get temporary links to remote files.
Command.new( 'media REMOTE_FILE...', "Create Dropbox links to publicly share remote files. The links are \ time-limited and link directly to the files themselves.", lambda do |client, state, args| extract_flags(MEDIA.usage, args, {}) state.(args).each do |path| if path.is_a?(GlobError) warn "media: #{path}: no such file or directory" else try_and_handle(DropboxError) do url = client.media(path)['url'] puts "#{File.basename(path)} -> #{url}" end end end end )
- MKDIR =
Create a remote directory.
Command.new( 'mkdir REMOTE_DIR...', 'Create remote directories.', lambda do |client, state, args| extract_flags(MKDIR.usage, args, {}) args.each do |arg| try_and_handle(DropboxError) do path = state.resolve_path(arg) = client.file_create_folder(path) state.cache.add() end end end )
- MV =
Move/rename remote files.
Command.new( 'mv [-f] REMOTE_FILE... REMOTE_FILE', "When given two arguments, moves the remote file or folder at the first \ path to the second path. When given more than two arguments or when the \ final argument is a directory, moves each remote file or folder into \ that directory. Will refuse to overwrite existing files unless invoked \ with the -f option.", lambda do |client, state, args| cp_mv(client, state, args, 'mv', MV.usage) end )
- PUT =
Upload a local file.
Command.new( 'put [-E] [-f] [-q] [-O REMOTE_DIR] [-t COUNT] LOCAL_FILE...', "Upload local files to the remote working directory. If a remote file of \ the same name already exists, Dropbox will rename the upload unless the \ the -f option is given, in which case the remote file will be \ overwritten. If the -E option is given, delete each local file after \ successful upload. If the -O option is given, the files will be uploaded \ to the given directory instead of the current directory. The -q option \ prevents progress from being printed. The -t option specifies the number \ of tries in case of error. The default is 5; -t 0 will retry infinitely.", lambda do |client, state, args| flags = extract_flags(PUT.usage, args, '-E' => 0, '-f' => 0, '-q' => 0, '-O' => 1, '-t' => 1) dest_index = flags.find_index('-O') dest_path = nil unless dest_index.nil? dest_path = flags[dest_index + 1] if state.directory?(dest_path) state.pwd = state.resolve_path(dest_path) else warn "put: #{dest_path}: no such directory" return end end tries_index = flags.find_index('-t') tries = tries_index ? flags[tries_index + 1].to_i : 5 # Glob arguments. args.map! do |arg| array = Dir.glob(File.(arg)) warn "put: #{arg}: no such file or directory" if array.empty? array.map { |path| path.sub(File.dirname(path), File.dirname(arg)) } end args = args.reduce(:+) args.each do |arg| to_path = state.resolve_path(File.basename(arg)) try_and_handle(StandardError) do path = File.(arg) if File.directory?(path) warn "put: #{arg}: cannot put directory" next end success = false File.open(path, 'rb') do |file| if flags.include?('-f') && state.(to_path) client.file_delete(to_path) state.cache.remove(to_path) end # Chunked upload if file is more than 1M. if file.size > 1024 * 1024 data, success = chunked_upload(client, to_path, file, flags.include?('-q'), tries) else data = client.put_file(to_path, file) success = true end state.cache.add(data) puts "#{arg} -> #{data['path']}" end File.delete(path) if flags.include?('-E') && success end end state.pwd = state.oldpwd unless dest_path.nil? end )
- RESTORE =
Restore a remove file to a previous version.
Command.new( 'restore REMOTE_FILE REVISION_ID', "Restore a remote file to a previous version. Use the 'history' command \ to get a list of IDs for previous revisions of the file.", lambda do |client, state, args| extract_flags(RESTORE.usage, args, {}) path = state.resolve_path(args.first) if !state.(path) || state.directory?(path) warn "restore: #{args.first}: no such file" else try_and_handle(DropboxError) do client.restore(path, args.last) end end end )
- RM =
Remove remote files.
Command.new( 'rm [-r] REMOTE_FILE...', "Remove each specified remote file. If the -r option is given, will \ also remove directories recursively.", lambda do |client, state, args| flags = extract_flags(RM.usage, args, '-r' => 0) state.(args).each do |path| if path.is_a?(GlobError) warn "rm: #{path}: no such file or directory" else if state.directory?(path) && !flags.include?('-r') warn "rm: #{path}: is a directory" next end try_and_handle(DropboxError) do client.file_delete(path) state.cache.remove(path) end end end check_pwd(state) end )
- RMDIR =
Remove remote directories.
Command.new( 'rmdir REMOTE_DIR...', 'Remove each specified empty remote directory.', lambda do |client, state, args| extract_flags(RMDIR.usage, args, {}) state.(args).each do |path| if path.is_a?(GlobError) warn "rmdir: #{path}: no such file or directory" else unless state.directory?(path) warn "rmdir: #{path}: not a directory" next end contents = state.(path)['contents'] if contents && !contents.empty? warn "rmdir: #{path}: directory not empty" next end try_and_handle(DropboxError) do client.file_delete(path) state.cache.remove(path) end end end check_pwd(state) end )
- SEARCH =
Search for remote files.
Command.new( 'search REMOTE_DIR SUBSTRING...', "List remote files in a directory or its subdirectories with names that \ contain all given substrings.", lambda do |client, state, args| extract_flags(SEARCH.usage, args, {}) path = state.resolve_path(args.first) unless state.directory?(path) warn "search: #{args.first}: no such directory" return end query = args.drop(1).join(' ') try_and_handle(DropboxError) do client.search(path, query).each { |result| puts result['path'] } end end )
- SHARE =
Get permanent links to remote files.
Command.new( 'share REMOTE_FILE...', "Create Dropbox links to publicly share remote files. The links are \ shortened and direct to 'preview' pages of the files. Links created by \ this method are set to expire far enough in the future so that \ expiration is effectively not an issue.", lambda do |client, state, args| extract_flags(SHARE.usage, args, {}) state.(args).each do |path| if path.is_a?(GlobError) warn "share: #{path}: no such file or directory" else try_and_handle(DropboxError) do url = client.shares(path)['url'] puts "#{File.basename(path)} -> #{url}" end end end end )
- NAMES =
Array
of all command names. names
Class Method Summary collapse
-
.exec(input, client, state) ⇒ Object
Parse and execute a line of user input in the given context.
-
.names ⇒ Object
Return an
Array
of all command names.
Class Method Details
.exec(input, client, state) ⇒ Object
Parse and execute a line of user input in the given context.
568 569 570 571 572 573 574 575 576 |
# File 'lib/droxi/commands.rb', line 568 def self.exec(input, client, state) if input.start_with?('!') shell(input[1, input.size - 1]) { |line| puts line } elsif !input.empty? tokens = Text.tokenize(input) cmd, args = tokens.first, tokens.drop(1) try_command(cmd, args, client, state) end end |
.names ⇒ Object
Return an Array
of all command names.
559 560 561 562 |
# File 'lib/droxi/commands.rb', line 559 def self.names symbols = constants.select { |sym| const_get(sym).is_a?(Command) } symbols.map { |sym| sym.to_s.downcase } end |