scripto 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4303784647ebd8ea25f1231f1c457490a15aebb8
4
- data.tar.gz: 8503790cde1ec50455970da18a6d038ad6699cf1
3
+ metadata.gz: bd230249468a8975ef75cad139685d21a535842b
4
+ data.tar.gz: f9c7c8a34a06b1892b2302a70dbf09ce8c6be066
5
5
  SHA512:
6
- metadata.gz: 5d9162c98b08f8f027d9233f5eca62db3485616dccecbb42a502e2d38db6734296575642a2f31563a39d04f0789a745ce62d5acfe95e1cb86a7c85bc74605b98
7
- data.tar.gz: d047ea1eca14ef498dc563cb26c20b1864763d509a5649e798390193825a4e1031fd6554d8ab77803847d0e2ed68c301523873db23735c3256d869b3d97a24f2
6
+ metadata.gz: 353e0017433d1a40c4a02c31543a174774f3261d70ec722af53703499f24e65a94cd7d024ef41de9479522865f70907c292e783f72f444b8fccf0831e3ae262c
7
+ data.tar.gz: 22d9cae0e3a74b4aa41e410cd1cb9d6671481d58a61477e7c1af681311abd0c04db79365f025122b6b6fd92bed1aff37bfc2436e09d9bd42257527f99615fced
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  *.rbc
3
3
  .bundle
4
4
  .config
5
+ .vagrant
5
6
  .yardoc
6
7
  Gemfile.lock
7
8
  InstalledFiles
data/README.md CHANGED
@@ -1,29 +1,151 @@
1
1
  # Scripto
2
2
 
3
- TODO: Write a gem description
3
+ Scripto is a framework for writing command line applications. It fills in many of the blanks that Ruby's standard library is missing:
4
4
 
5
- ## Installation
5
+ * **print to $stderr** - Colored banners and a verbose mode to make your scripts louder.
6
+ * **file operations** - Mkdir, cp, mv, ln. These operations can take care of common edge cases, like creating the target directory before copying a file.
7
+ * **csv** - Read and write CSV files from hashes, Structs, or OpenStructs.
8
+ * **run commands** - Run external commands and raise errors on failure.
6
9
 
7
- Add this line to your application's Gemfile:
10
+ ## Getting Started
8
11
 
9
- gem 'scripto'
12
+ You can call Scripto directly:
10
13
 
11
- And then execute:
14
+ ```ruby
15
+ require "scripto"
12
16
 
13
- $ bundle
17
+ Scripto.banner("Starting installation...")
18
+ Scripto.cp("here.txt", "there.txt")
19
+ Scripto.mv("there.txt", "and_back.txt")
14
20
 
15
- Or install it yourself as:
21
+ rows = [ ]
22
+ rows << { name: "Adam", score: 100 }
23
+ rows << { name: "Patrick", score: 99 }
24
+ Scripto.csv_write("scores.csv", rows)
16
25
 
17
- $ gem install scripto
26
+ if Scripto.fails("which git")
27
+ Scripto.run("brew install git")
28
+ end
18
29
 
19
- ## Usage
30
+ Scripto.run("touch script_complete.txt")
31
+ ```
20
32
 
21
- TODO: Write usage instructions here
33
+ You can also subclass `Scripto::Main`:
22
34
 
23
- ## Contributing
35
+ ```ruby
36
+ #!/usr/bin/env ruby
24
37
 
25
- 1. Fork it ( http://github.com/<my-github-username>/scripto/fork )
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Add some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
38
+ require "scripto"
39
+
40
+ class Install < Scripto::Main
41
+ def initialize(options = {})
42
+ verbose! if options[:verbose]
43
+
44
+ banner("Starting installation...")
45
+ cp("here.txt", "there.txt")
46
+ mv("there.txt", "and_back.txt")
47
+
48
+ rows = [ ]
49
+ rows << { name: "Adam", score: 100 }
50
+ rows << { name: "Patrick", score: 99 }
51
+ csv_write("scores.csv", rows)
52
+
53
+ if fails("which git")
54
+ run("brew install git")
55
+ end
56
+
57
+ run("touch script_complete.txt")
58
+ end
59
+ end
60
+
61
+ Install.new(verbose: true)
62
+ ```
63
+
64
+ ## Methods
65
+
66
+ ### Print to $stderr
67
+
68
+ ```
69
+ banner(str) - print a banner in green
70
+ warning(str) - print a warning in yellow
71
+ fatal(str) - print a fatal error in red, then exit(1)
72
+
73
+ verbose! - turn on verbose mode
74
+ vbanner(str) - print a colored banner in green if verbose is on
75
+ vprintf(str) - printf if verbose is on
76
+ vputs(str) - puts if verbose is on
77
+ ```
78
+
79
+ ### File operations
80
+
81
+ These operations are silent by default. If verbose is turned on, each command will be echoed first.
82
+
83
+ ```
84
+ mkdir(dir) - mkdir -p dir
85
+ cp(src, dst, mkdir: false) - cp -p src dst, mkdir if necessary
86
+ mv(src, dst, mkdir: false) - mv src dst, mkdir if necessary
87
+ ln(src, dst, mkdir: false) - ln -sf src dst, mkdir if necessary
88
+ rm(file) - rm -f file
89
+ ```
90
+
91
+ Each of these operations also has an "if_necessary" variant that only runs the operation if necessary. For example, `mkdir_if_necessary` only calls `mkdir` if the directory doesn't exist. When combined with verbose mode, this produces **a nice changelog** as the operations are run. You can run your script repeatedly and it'll only output actual changes.
92
+
93
+ Plus a few more:
94
+
95
+ ```
96
+ chown(file, user) - chown user:user file
97
+ chmod(file, mode) - chmod mode file
98
+ rm_and_mkdir(dir) - rm -rf dir && mkdir -p dir (for tmp dirs)
99
+ copy_metadata(src, dst) - copy mode/atime/mtime from src to dst
100
+ ```
101
+
102
+ ### Run external commands (system, backtick, etc)
103
+
104
+ Each of these methods takes a `command` and an optional array of `args`. Use it like so:
105
+
106
+ ```
107
+ run("echo hello world") # this will use a shell
108
+ run("echo, ["hello", "world"]) # NO shell, runs echo directly
109
+ ```
110
+
111
+ This is like `Kernel#system` works - you can use the second variant (the array of arguments) to sidestep shell escaping issues. For example, these are the same but the second variant doesn't require those pesky single quotes:
112
+
113
+ ```
114
+ run("cp file 'hello world")
115
+ run("cp, ["file", "hello world"])
116
+ ```
117
+
118
+ Here are the various run commands:
119
+
120
+ ```
121
+ run(command, args = nil) - run a command, raise an error
122
+ run_capture(command, args = nil) - capture the output similar to backtick, raise on error
123
+ run_quietly(command, args = nil) - redirect stdout/stderr to /dev/null, raise on error
124
+
125
+ run_succeeds?(command, args = nil) - return true if command succeeds
126
+ run_fails?(command, args = nil) - return true if command fails
127
+ ```
128
+
129
+ ### CSV read/write
130
+
131
+ Light wrappers around the CSV class built into Ruby. Used exclusively with hash-like objects, not arrays. The header row turns into the keys for the hash.
132
+
133
+ ```
134
+ csv_read(path) - read a CSV, returns an array of Structs. Path can be a .gz.
135
+ csv_write(path, rows) - write rows to a CSV. Rows can be hashes, Structs or OpenStructs.
136
+ csv_to_stdout(rows) - write rows to stdout, like csv_write
137
+ csv_to_s(rows) - write rows to a string, like csv_write
138
+ ```
139
+
140
+ ### Misc
141
+
142
+ There are a few more useful tidbits in here:
143
+
144
+ ```
145
+ whoami - just like the command
146
+ root? - return true if we're running as root
147
+ md5_file(path) - calculate md5 for a file
148
+ md5_string(str) - calculate md5 for a string
149
+ prompt?(question) - ask the user a question, return true if they say yes
150
+ random_string(len) - calculate a random alphanumeric string
151
+ ```
data/Rakefile CHANGED
@@ -10,5 +10,7 @@ task default: :test
10
10
  RDoc::Task.new do |rdoc|
11
11
  rdoc.rdoc_dir = "rdoc"
12
12
  rdoc.title = "scripto #{Scripto::VERSION}"
13
+ rdoc.main = "README.md"
13
14
  rdoc.rdoc_files.include("lib/**/*.rb")
15
+ rdoc.rdoc_files.include("README.md")
14
16
  end
@@ -0,0 +1,121 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+
4
+ # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
5
+ VAGRANTFILE_API_VERSION = "2"
6
+
7
+ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
8
+ # All Vagrant configuration is done here. The most common configuration
9
+ # options are documented and commented below. For a complete reference,
10
+ # please see the online documentation at vagrantup.com.
11
+
12
+ # Every Vagrant virtual environment requires a box to build off of.
13
+ config.vm.box = "precise32"
14
+
15
+ # The url from where the 'config.vm.box' box will be fetched if it
16
+ # doesn't already exist on the user's system.
17
+ config.vm.box_url = "http://files.vagrantup.com/precise32.box"
18
+
19
+ # amd
20
+ config.vm.provision :shell, path: "vagrant_provision", privileged: false
21
+
22
+ # Create a forwarded port mapping which allows access to a specific port
23
+ # within the machine from a port on the host machine. In the example below,
24
+ # accessing "localhost:8080" will access port 80 on the guest machine.
25
+ # config.vm.network :forwarded_port, guest: 80, host: 8080
26
+
27
+ # Create a private network, which allows host-only access to the machine
28
+ # using a specific IP.
29
+ # config.vm.network :private_network, ip: "192.168.33.10"
30
+
31
+ # Create a public network, which generally matched to bridged network.
32
+ # Bridged networks make the machine appear as another physical device on
33
+ # your network.
34
+ # config.vm.network :public_network
35
+
36
+ # If true, then any SSH connections made will enable agent forwarding.
37
+ # Default value: false
38
+ # config.ssh.forward_agent = true
39
+
40
+ # Share an additional folder to the guest VM. The first argument is
41
+ # the path on the host to the actual folder. The second argument is
42
+ # the path on the guest to mount the folder. And the optional third
43
+ # argument is a set of non-required options.
44
+ # config.vm.synced_folder "../data", "/vagrant_data"
45
+
46
+ # Provider-specific configuration so you can fine-tune various
47
+ # backing providers for Vagrant. These expose provider-specific options.
48
+ # Example for VirtualBox:
49
+ #
50
+ # config.vm.provider :virtualbox do |vb|
51
+ # # Don't boot with headless mode
52
+ # vb.gui = true
53
+ #
54
+ # # Use VBoxManage to customize the VM. For example to change memory:
55
+ # vb.customize ["modifyvm", :id, "--memory", "1024"]
56
+ # end
57
+ #
58
+ # View the documentation for the provider you're using for more
59
+ # information on available options.
60
+
61
+ # Enable provisioning with Puppet stand alone. Puppet manifests
62
+ # are contained in a directory path relative to this Vagrantfile.
63
+ # You will need to create the manifests directory and a manifest in
64
+ # the file precise32.pp in the manifests_path directory.
65
+ #
66
+ # An example Puppet manifest to provision the message of the day:
67
+ #
68
+ # # group { "puppet":
69
+ # # ensure => "present",
70
+ # # }
71
+ # #
72
+ # # File { owner => 0, group => 0, mode => 0644 }
73
+ # #
74
+ # # file { '/etc/motd':
75
+ # # content => "Welcome to your Vagrant-built virtual machine!
76
+ # # Managed by Puppet.\n"
77
+ # # }
78
+ #
79
+ # config.vm.provision :puppet do |puppet|
80
+ # puppet.manifests_path = "manifests"
81
+ # puppet.manifest_file = "site.pp"
82
+ # end
83
+
84
+ # Enable provisioning with chef solo, specifying a cookbooks path, roles
85
+ # path, and data_bags path (all relative to this Vagrantfile), and adding
86
+ # some recipes and/or roles.
87
+ #
88
+ # config.vm.provision :chef_solo do |chef|
89
+ # chef.cookbooks_path = "../my-recipes/cookbooks"
90
+ # chef.roles_path = "../my-recipes/roles"
91
+ # chef.data_bags_path = "../my-recipes/data_bags"
92
+ # chef.add_recipe "mysql"
93
+ # chef.add_role "web"
94
+ #
95
+ # # You may also specify custom JSON attributes:
96
+ # chef.json = { :mysql_password => "foo" }
97
+ # end
98
+
99
+ # Enable provisioning with chef server, specifying the chef server URL,
100
+ # and the path to the validation key (relative to this Vagrantfile).
101
+ #
102
+ # The Opscode Platform uses HTTPS. Substitute your organization for
103
+ # ORGNAME in the URL and validation key.
104
+ #
105
+ # If you have your own Chef Server, use the appropriate URL, which may be
106
+ # HTTP instead of HTTPS depending on your configuration. Also change the
107
+ # validation key to validation.pem.
108
+ #
109
+ # config.vm.provision :chef_client do |chef|
110
+ # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
111
+ # chef.validation_key_path = "ORGNAME-validator.pem"
112
+ # end
113
+ #
114
+ # If you're using the Opscode platform, your validator client is
115
+ # ORGNAME-validator, replacing ORGNAME with your organization name.
116
+ #
117
+ # If you have your own Chef Server, the default validation client name is
118
+ # chef-validator, unless you changed the configuration.
119
+ #
120
+ # chef.validation_client_name = "ORGNAME-validator"
121
+ end
@@ -1,9 +1,10 @@
1
1
  require "csv"
2
- require "ostruct"
3
2
  require "zlib"
4
3
 
5
4
  module Scripto
6
5
  module CsvCommands
6
+ # Read a csv from +path+. Returns an array of Structs, using the keys from
7
+ # the csv header row.
7
8
  def csv_read(path)
8
9
  lines = if path =~ /\.gz$/
9
10
  Zlib::GzipReader.open(path) do |f|
@@ -17,7 +18,10 @@ module Scripto
17
18
  lines.map { |i| klass.new(*i) }
18
19
  end
19
20
 
20
- # write rows to path as CSV
21
+ # Write +rows+ to +path+ as csv. Rows can be an array of hashes, Structs,
22
+ # OpenStructs, or anything else that responds to to_h. The keys from the
23
+ # first row are used as the csv header. If +cols+ is specified, it will be
24
+ # used as the column keys instead.
21
25
  def csv_write(path, rows, cols: nil)
22
26
  begin
23
27
  tmp = "/tmp/_scripto_csv.csv"
@@ -28,10 +32,12 @@ module Scripto
28
32
  end
29
33
  end
30
34
 
35
+ # Write +rows+ to $stdout as a csv. Similar to csv_write.
31
36
  def csv_to_stdout(rows, cols: nil)
32
37
  CSV($stdout) { |f| csv_write0(f, rows, cols: cols) }
33
38
  end
34
39
 
40
+ # Returns a string containing +rows+ as a csv. Similar to csv_write.
35
41
  def csv_to_s(rows, cols: nil)
36
42
  string = ""
37
43
  f = CSV.new(StringIO.new(string))
@@ -41,6 +47,7 @@ module Scripto
41
47
 
42
48
  protected
43
49
 
50
+ # :nodoc:
44
51
  def csv_write0(csv, rows, cols: nil)
45
52
  # cols
46
53
  cols ||= rows.first.to_h.keys
@@ -3,12 +3,21 @@ require "fileutils"
3
3
 
4
4
  module Scripto
5
5
  module FileCommands
6
+ # Like mkdir -p +dir+. If +owner+ is specified, the directory will be
7
+ # chowned to owner. If +mode+ is specified, the directory will be chmodded
8
+ # to mode. Like all file commands, the operation will be printed out if
9
+ # verbose?.
6
10
  def mkdir(dir, owner: nil, mode: nil)
7
11
  FileUtils.mkdir_p(dir, verbose: verbose?)
8
12
  chown(dir, owner) if owner
9
13
  chmod(dir, mode) if mode
10
14
  end
11
15
 
16
+ # Like cp -pr +src+ +dst. If +mkdir+ is true, the dst directoy will be
17
+ # created if necessary before the copy. If +owner+ is specified, the
18
+ # directory will be chowned to owner. If +mode+ is specified, the
19
+ # directory will be chmodded to mode. Like all file commands, the
20
+ # operation will be printed out if verbose?.
12
21
  def cp(src, dst, mkdir: false, owner: nil, mode: nil)
13
22
  mkdir_if_necessary(File.dirname(dst)) if mkdir
14
23
  FileUtils.cp_r(src, dst, preserve: true, verbose: verbose?)
@@ -16,11 +25,16 @@ module Scripto
16
25
  chmod(dst, mode) if mode
17
26
  end
18
27
 
28
+ # Like mv +src+ +dst. If +mkdir+ is true, the dst directoy will be created
29
+ # if necessary before the copy. Like all file commands, the operation will
30
+ # be printed out if verbose?.
19
31
  def mv(src, dst, mkdir: false)
20
32
  mkdir_if_necessary(File.dirname(dst)) if mkdir
21
33
  FileUtils.mv(src, dst, verbose: verbose?)
22
34
  end
23
35
 
36
+ # Like ln -sf +src+ +dst. The command will be printed out if
37
+ # verbose?.
24
38
  def ln(src, dst)
25
39
  begin
26
40
  FileUtils.ln_sf(src, dst, verbose: verbose?)
@@ -31,10 +45,15 @@ module Scripto
31
45
  end
32
46
  end
33
47
 
48
+ # Like rm -f +file+. Like all file commands, the operation will be printed
49
+ # out if verbose?.
34
50
  def rm(file)
35
51
  FileUtils.rm_f(file, verbose: verbose?)
36
52
  end
37
53
 
54
+ # Runs #mkdir, but ONLY if +dir+ doesn't already exist. Returns true if
55
+ # directory had to be created. This is useful with verbose?, to get an
56
+ # exact changelog.
38
57
  def mkdir_if_necessary(dir, owner: nil, mode: nil)
39
58
  if !(File.exists?(dir) || File.symlink?(dir))
40
59
  mkdir(dir, owner: owner, mode: mode)
@@ -42,6 +61,9 @@ module Scripto
42
61
  end
43
62
  end
44
63
 
64
+ # Runs #cp, but ONLY if +dst+ doesn't exist or differs from +src+. Returns
65
+ # true if the file had to be copied. This is useful with verbose?, to get
66
+ # an exact changelog.
45
67
  def cp_if_necessary(src, dst, mkdir: false, owner: nil, mode: nil)
46
68
  if !(File.exists?(dst) && FileUtils.compare_file(src, dst))
47
69
  cp(src, dst, mkdir: mkdir, owner: owner, mode: mode)
@@ -49,6 +71,9 @@ module Scripto
49
71
  end
50
72
  end
51
73
 
74
+ # Runs #ln, but ONLY if +dst+ isn't a symlink or differs from +src+.
75
+ # Returns true if the file had to be symlinked. This is useful with
76
+ # verbose?, to get an exact changelog.
52
77
  def ln_if_necessary(src, dst)
53
78
  ln = if !File.symlink?(dst)
54
79
  true
@@ -62,6 +87,8 @@ module Scripto
62
87
  end
63
88
  end
64
89
 
90
+ # Runs #rm, but ONLY if +file+ exists. Return true if the file had to be
91
+ # removed. This is useful with verbose?, to get an exact changelog.
65
92
  def rm_if_necessary(file)
66
93
  if File.exists?(file)
67
94
  rm(file)
@@ -69,6 +96,8 @@ module Scripto
69
96
  end
70
97
  end
71
98
 
99
+ # Like chown user:user file. Like all file commands, the operation will be printed
100
+ # out if verbose?.
72
101
  def chown(file, user)
73
102
  # who is the current owner?
74
103
  @scripto_uids ||= {}
@@ -79,18 +108,24 @@ module Scripto
79
108
  end
80
109
  end
81
110
 
111
+ # Like chmod mode file. Like all file commands, the operation will be
112
+ # printed out if verbose?.
82
113
  def chmod(file, mode)
83
114
  if File.stat(file).mode != mode
84
115
  FileUtils.chmod(mode, file, verbose: verbose?)
85
116
  end
86
117
  end
87
118
 
119
+ # Like rm -rf && mkdir -p. Like all file commands, the operation will be
120
+ # printed out if verbose?.
88
121
  def rm_and_mkdir(dir)
89
122
  raise "don't do this" if dir == ""
90
123
  FileUtils.rm_rf(dir, verbose: verbose?)
91
124
  mkdir(dir)
92
125
  end
93
126
 
127
+ # Copy mode, atime and mtime from +src+ to +dst+. This one is rarely used
128
+ # and doesn't echo.
94
129
  def copy_metadata(src, dst)
95
130
  stat = File.stat(src)
96
131
  File.chmod(stat.mode, dst)
@@ -1,4 +1,6 @@
1
1
  module Scripto
2
+ # A convenient superclass for using Scripto. Just subclass Main and you have
3
+ # access to all the Scripto goodies.
2
4
  class Main
3
5
  include CsvCommands
4
6
  include FileCommands
@@ -5,14 +5,17 @@ module Scripto
5
5
  module MiscCommands
6
6
  BASE_62 = ("0".."9").to_a + ("A".."Z").to_a + ("a".."z").to_a
7
7
 
8
+ # Who is the current user?
8
9
  def whoami
9
10
  @scripto_whoami ||= Etc.getpwuid(Process.uid).name
10
11
  end
11
12
 
13
+ # Return true if the current user is "root".
12
14
  def root?
13
15
  whoami == "root"
14
16
  end
15
17
 
18
+ # Return the md5 checksum for the file at +path+.
16
19
  def md5_file(path)
17
20
  File.open(path) do |f|
18
21
  digest, buf = Digest::MD5.new, ""
@@ -23,16 +26,20 @@ module Scripto
23
26
  end
24
27
  end
25
28
 
26
- def md5_string(s)
27
- Digest::MD5.hexdigest(s.to_s)
29
+ # Return the md5 checksum for +str+.
30
+ def md5_string(str)
31
+ Digest::MD5.hexdigest(str.to_s)
28
32
  end
29
33
 
34
+ # Ask the user a question via stderr, then return true if they enter YES,
35
+ # yes, y, etc.
30
36
  def prompt?(question)
31
37
  $stderr.write("#{question} (y/n) ")
32
38
  $stderr.flush
33
39
  $stdin.gets =~ /^y/i
34
40
  end
35
41
 
42
+ # Return a random alphanumeric string of length +len+.
36
43
  def random_string(len)
37
44
  (1..len).map { BASE_62.sample }.join
38
45
  end
@@ -7,38 +7,47 @@ module Scripto
7
7
 
8
8
  attr_accessor :verbose
9
9
 
10
+ # Is verbose mode turned on?
10
11
  def verbose?
11
12
  !!@verbose
12
13
  end
13
14
 
15
+ # Turn on verbose mode. #vbanner, #vputs and #vprintf will start printing
16
+ # now, and file ops will be printed too.
14
17
  def verbose!
15
18
  @verbose = true
16
19
  end
17
20
 
18
- def vbanner(s = nil)
19
- banner(s) if verbose?
21
+ # Print a colored banner to $stderr, but only if #verbose?.
22
+ def vbanner(str = nil)
23
+ banner(str) if verbose?
20
24
  end
21
25
 
22
- def vputs(s = nil)
23
- $stderr.puts(s) if verbose?
26
+ # Puts to $stderr, but only if #verbose?.
27
+ def vputs(str = nil)
28
+ $stderr.puts(str) if verbose?
24
29
  end
25
30
 
26
- def vprintf(s, *args)
27
- $stderr.printf(s, *args) if verbose?
31
+ # Printf to $stderr, but only if #verbose?.
32
+ def vprintf(str, *args)
33
+ $stderr.printf(str, *args) if verbose?
28
34
  end
29
35
 
30
- def banner(s, color: GREEN)
36
+ # Print a colored banner to $stderr in green.
37
+ def banner(str, color: GREEN)
31
38
  now = Time.new.strftime("%H:%M:%S")
32
- s = "#{s} ".ljust(72, " ")
39
+ s = "#{str} ".ljust(72, " ")
33
40
  $stderr.puts "#{color}[#{now}] #{s}#{RESET}"
34
41
  end
35
42
 
36
- def warning(msg)
37
- banner("Warning: #{msg}", color: YELLOW)
43
+ # Print a yellow warning banner to $stderr.
44
+ def warning(str)
45
+ banner("Warning: #{str}", color: YELLOW)
38
46
  end
39
47
 
40
- def fatal(msg)
41
- banner(msg, color: RED)
48
+ # Print a red error banner to $stderr, then exit.
49
+ def fatal(str)
50
+ banner(str, color: RED)
42
51
  exit(1)
43
52
  end
44
53
  end
@@ -1,25 +1,38 @@
1
- require "english"
1
+ require "English"
2
2
  require "shellwords"
3
3
 
4
4
  module Scripto
5
5
  module RunCommands
6
- class Error < StandardError ; end
6
+ # The error thrown by #run, #run_capture and #run_quietly on failure.
7
+ class Error < StandardError
8
+ end
7
9
 
10
+ # Run an external command. Raise Error if something goes wrong. The
11
+ # command will be echoed if verbose?.
12
+ #
13
+ # Usage is similar to Kernel#system. If +args+ is nil, +command+ will be
14
+ # passed to the shell. If +args+ are included, the +command+ and +args+
15
+ # will be run directly without the shell.
8
16
  def run(command, args = nil)
9
17
  cmd = CommandLine.new(command, args)
10
18
  vputs(cmd)
11
19
  cmd.run
12
20
  end
13
21
 
22
+ # Run a command and capture the output like backticks. See #run
23
+ # for details.
14
24
  def run_capture(command, args = nil)
15
25
  CommandLine.new(command, args).capture
16
26
  end
17
27
 
28
+ # Run a command and suppress output by redirecting to /dev/null. See #run
29
+ # for details.
18
30
  def run_quietly(command, args = nil)
19
31
  cmd = CommandLine.new(command, args)
20
32
  run("#{cmd} > /dev/null 2> /dev/null")
21
33
  end
22
34
 
35
+ # Returns true if the command succeeds. See #run for details.
23
36
  def run_succeeds?(command, args = nil)
24
37
  begin
25
38
  run_quietly(command, args)
@@ -29,16 +42,19 @@ module Scripto
29
42
  end
30
43
  end
31
44
 
45
+ # Returns true if the command fails. See #run for details.
32
46
  def run_fails?(command, args = nil)
33
47
  !run_succeeds?(command, args)
34
48
  end
35
49
 
36
- def shellescape(s)
37
- Shellwords.escape(s)
50
+ # Escape str if necessary. Useful for passing arguments to a shell.
51
+ def shellescape(str)
52
+ Shellwords.escape(str)
38
53
  end
39
54
 
40
55
  protected
41
56
 
57
+ # :nodoc:
42
58
  class CommandLine
43
59
  attr_accessor :command, :args
44
60
 
@@ -1,3 +1,4 @@
1
1
  module Scripto
2
- VERSION = "0.0.1"
2
+ # current Scripto version
3
+ VERSION = "0.0.2"
3
4
  end
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.required_ruby_version = ">= 2.0.0"
11
11
  spec.authors = ["Adam Doppelt"]
12
12
  spec.email = ["amd@gurge.com"]
13
- spec.summary = "Helpers for writing command line scripts."
13
+ spec.summary = "Helpers for writing command line scripts. An extraction from Dwellable."
14
14
  spec.homepage = "http://github.com/gurgeous/scripto"
15
15
  spec.license = "MIT"
16
16
 
@@ -11,14 +11,14 @@ class TestPrint < Minitest::Test
11
11
 
12
12
  def test_quiet
13
13
  assert_silent { Scripto.vbanner "gub" }
14
- assert_silent { Scripto.vprintf "gub" }
14
+ assert_silent { Scripto.vprintf("gub %d", 123) }
15
15
  assert_silent { Scripto.vputs "gub" }
16
16
  end
17
17
 
18
18
  def test_loud
19
19
  Scripto.verbose!
20
20
  assert_output(nil, /gub/) { Scripto.vbanner "gub" }
21
- assert_output(nil, /gub/) { Scripto.vprintf "gub" }
21
+ assert_output(nil, /gub/) { Scripto.vprintf("zub %s", "gub") }
22
22
  assert_output(nil, /gub/) { Scripto.vputs "gub" }
23
23
  end
24
24
 
@@ -0,0 +1,50 @@
1
+ #!/bin/bash
2
+
3
+ # bail on errors
4
+ set -eu
5
+
6
+ function banner() {
7
+ printf '\e[1;37;43m[%s] %-72s\e[0m\n' `date '+%H:%M:%S'` "vagrant_provision: $1"
8
+ }
9
+
10
+ # packages needed for building ruby
11
+ banner "Packages..."
12
+ sudo apt-get -y install git-core
13
+ sudo apt-get -y install build-essential checkinstall libffi-dev libreadline-gplv2-dev libncurses5-dev libssl-dev libyaml-dev zlib1g-dev
14
+
15
+ # rbenv
16
+ banner "Rbenv..."
17
+ if [ ! -d ~/.rbenv ] ; then
18
+ git clone git://github.com/sstephenson/rbenv.git ~/.rbenv
19
+ fi
20
+ if [ ! -d ~/.rbenv/plugins/ruby-build ] ; then
21
+ git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
22
+ fi
23
+
24
+ # add rbenv to .bashrc
25
+ if ! grep -q 'vagrant provisioning' ~/.bashrc ; then
26
+ cat >> ~/.bashrc <<"EOF"
27
+ # added by vagrant provisioning
28
+ export PATH="$HOME/.rbenv/bin:$PATH"
29
+ eval "$(rbenv init -)"
30
+ EOF
31
+
32
+ # make sure we pickup rbenv too!
33
+ export PATH="$HOME/.rbenv/bin:$PATH"
34
+ eval "$(rbenv init -)"
35
+ fi
36
+
37
+ # no rdoc, please
38
+ echo 'gem: --no-ri --no-rdoc' > ~/.gemrc
39
+
40
+ # now install ruby
41
+ banner "Ruby..."
42
+ rbenv install 2.0.0-p353
43
+ rbenv global 2.0.0-p353
44
+ ruby -v
45
+
46
+ # and gems
47
+ banner "Gems..."
48
+ gem update --system
49
+ gem install bundler
50
+ rbenv rehash
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scripto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Doppelt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-11 00:00:00.000000000 Z
11
+ date: 2014-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -64,6 +64,7 @@ files:
64
64
  - LICENSE.txt
65
65
  - README.md
66
66
  - Rakefile
67
+ - Vagrantfile
67
68
  - lib/scripto.rb
68
69
  - lib/scripto/csv_commands.rb
69
70
  - lib/scripto/file_commands.rb
@@ -79,6 +80,7 @@ files:
79
80
  - test/test_misc.rb
80
81
  - test/test_print.rb
81
82
  - test/test_run.rb
83
+ - vagrant_provision
82
84
  homepage: http://github.com/gurgeous/scripto
83
85
  licenses:
84
86
  - MIT
@@ -102,7 +104,7 @@ rubyforge_project:
102
104
  rubygems_version: 2.2.1
103
105
  signing_key:
104
106
  specification_version: 4
105
- summary: Helpers for writing command line scripts.
107
+ summary: Helpers for writing command line scripts. An extraction from Dwellable.
106
108
  test_files:
107
109
  - test/helper.rb
108
110
  - test/test_csv.rb