scripto 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4303784647ebd8ea25f1231f1c457490a15aebb8
4
+ data.tar.gz: 8503790cde1ec50455970da18a6d038ad6699cf1
5
+ SHA512:
6
+ metadata.gz: 5d9162c98b08f8f027d9233f5eca62db3485616dccecbb42a502e2d38db6734296575642a2f31563a39d04f0789a745ce62d5acfe95e1cb86a7c85bc74605b98
7
+ data.tar.gz: d047ea1eca14ef498dc563cb26c20b1864763d509a5649e798390193825a4e1031fd6554d8ab77803847d0e2ed68c301523873db23735c3256d869b3d97a24f2
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in scripto.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 amd
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # Scripto
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'scripto'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install scripto
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
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
@@ -0,0 +1,14 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+ require "rdoc/task"
4
+
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.libs << "test"
7
+ end
8
+ task default: :test
9
+
10
+ RDoc::Task.new do |rdoc|
11
+ rdoc.rdoc_dir = "rdoc"
12
+ rdoc.title = "scripto #{Scripto::VERSION}"
13
+ rdoc.rdoc_files.include("lib/**/*.rb")
14
+ end
@@ -0,0 +1,15 @@
1
+ require "scripto/csv_commands"
2
+ require "scripto/file_commands"
3
+ require "scripto/misc_commands"
4
+ require "scripto/print_commands"
5
+ require "scripto/run_commands"
6
+ require "scripto/version"
7
+ require "scripto/main"
8
+
9
+ module Scripto
10
+ extend CsvCommands
11
+ extend FileCommands
12
+ extend MiscCommands
13
+ extend PrintCommands
14
+ extend RunCommands
15
+ end
@@ -0,0 +1,56 @@
1
+ require "csv"
2
+ require "ostruct"
3
+ require "zlib"
4
+
5
+ module Scripto
6
+ module CsvCommands
7
+ def csv_read(path)
8
+ lines = if path =~ /\.gz$/
9
+ Zlib::GzipReader.open(path) do |f|
10
+ CSV.new(f).read
11
+ end
12
+ else
13
+ CSV.read(path)
14
+ end
15
+ keys = lines.shift.map(&:to_sym)
16
+ klass = Struct.new(*keys)
17
+ lines.map { |i| klass.new(*i) }
18
+ end
19
+
20
+ # write rows to path as CSV
21
+ def csv_write(path, rows, cols: nil)
22
+ begin
23
+ tmp = "/tmp/_scripto_csv.csv"
24
+ CSV.open(tmp, "wb") { |f| csv_write0(f, rows, cols: cols) }
25
+ mv(tmp, path)
26
+ ensure
27
+ rm_if_necessary(tmp)
28
+ end
29
+ end
30
+
31
+ def csv_to_stdout(rows, cols: nil)
32
+ CSV($stdout) { |f| csv_write0(f, rows, cols: cols) }
33
+ end
34
+
35
+ def csv_to_s(rows, cols: nil)
36
+ string = ""
37
+ f = CSV.new(StringIO.new(string))
38
+ csv_write0(f, rows, cols: cols)
39
+ string
40
+ end
41
+
42
+ protected
43
+
44
+ def csv_write0(csv, rows, cols: nil)
45
+ # cols
46
+ cols ||= rows.first.to_h.keys
47
+ csv << cols
48
+
49
+ # rows
50
+ rows.each do |row|
51
+ row = row.to_h
52
+ csv << cols.map { |i| row[i] }
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,100 @@
1
+ require "etc"
2
+ require "fileutils"
3
+
4
+ module Scripto
5
+ module FileCommands
6
+ def mkdir(dir, owner: nil, mode: nil)
7
+ FileUtils.mkdir_p(dir, verbose: verbose?)
8
+ chown(dir, owner) if owner
9
+ chmod(dir, mode) if mode
10
+ end
11
+
12
+ def cp(src, dst, mkdir: false, owner: nil, mode: nil)
13
+ mkdir_if_necessary(File.dirname(dst)) if mkdir
14
+ FileUtils.cp_r(src, dst, preserve: true, verbose: verbose?)
15
+ chown(dst, owner) if owner && !File.symlink?(dst)
16
+ chmod(dst, mode) if mode
17
+ end
18
+
19
+ def mv(src, dst, mkdir: false)
20
+ mkdir_if_necessary(File.dirname(dst)) if mkdir
21
+ FileUtils.mv(src, dst, verbose: verbose?)
22
+ end
23
+
24
+ def ln(src, dst)
25
+ begin
26
+ FileUtils.ln_sf(src, dst, verbose: verbose?)
27
+ rescue Errno::EEXIST => e
28
+ # It's a race - this can occur because ln_sf removes the old
29
+ # dst, then creates the symlink. Raise if they don't match.
30
+ raise e if !(File.symlink?(dst) && src == File.readlink(dst))
31
+ end
32
+ end
33
+
34
+ def rm(file)
35
+ FileUtils.rm_f(file, verbose: verbose?)
36
+ end
37
+
38
+ def mkdir_if_necessary(dir, owner: nil, mode: nil)
39
+ if !(File.exists?(dir) || File.symlink?(dir))
40
+ mkdir(dir, owner: owner, mode: mode)
41
+ true
42
+ end
43
+ end
44
+
45
+ def cp_if_necessary(src, dst, mkdir: false, owner: nil, mode: nil)
46
+ if !(File.exists?(dst) && FileUtils.compare_file(src, dst))
47
+ cp(src, dst, mkdir: mkdir, owner: owner, mode: mode)
48
+ true
49
+ end
50
+ end
51
+
52
+ def ln_if_necessary(src, dst)
53
+ ln = if !File.symlink?(dst)
54
+ true
55
+ elsif File.readlink(dst) != src
56
+ rm(dst)
57
+ true
58
+ end
59
+ if ln
60
+ ln(src, dst)
61
+ true
62
+ end
63
+ end
64
+
65
+ def rm_if_necessary(file)
66
+ if File.exists?(file)
67
+ rm(file)
68
+ true
69
+ end
70
+ end
71
+
72
+ def chown(file, user)
73
+ # who is the current owner?
74
+ @scripto_uids ||= {}
75
+ @scripto_uids[user] ||= Etc.getpwnam(user).uid
76
+ uid = @scripto_uids[user]
77
+ if File.stat(file).uid != uid
78
+ FileUtils.chown(uid, uid, file, verbose: verbose?)
79
+ end
80
+ end
81
+
82
+ def chmod(file, mode)
83
+ if File.stat(file).mode != mode
84
+ FileUtils.chmod(mode, file, verbose: verbose?)
85
+ end
86
+ end
87
+
88
+ def rm_and_mkdir(dir)
89
+ raise "don't do this" if dir == ""
90
+ FileUtils.rm_rf(dir, verbose: verbose?)
91
+ mkdir(dir)
92
+ end
93
+
94
+ def copy_metadata(src, dst)
95
+ stat = File.stat(src)
96
+ File.chmod(stat.mode, dst)
97
+ File.utime(stat.atime, stat.mtime, dst)
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,16 @@
1
+ module Scripto
2
+ class Main
3
+ include CsvCommands
4
+ include FileCommands
5
+ include MiscCommands
6
+ include PrintCommands
7
+ include RunCommands
8
+
9
+ attr_accessor :options
10
+
11
+ def initialize(options = {})
12
+ self.options = options
13
+ self.verbose = options[:verbose]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,40 @@
1
+ require "digest/md5"
2
+ require "etc"
3
+
4
+ module Scripto
5
+ module MiscCommands
6
+ BASE_62 = ("0".."9").to_a + ("A".."Z").to_a + ("a".."z").to_a
7
+
8
+ def whoami
9
+ @scripto_whoami ||= Etc.getpwuid(Process.uid).name
10
+ end
11
+
12
+ def root?
13
+ whoami == "root"
14
+ end
15
+
16
+ def md5_file(path)
17
+ File.open(path) do |f|
18
+ digest, buf = Digest::MD5.new, ""
19
+ while f.read(4096, buf)
20
+ digest.update(buf)
21
+ end
22
+ digest.hexdigest
23
+ end
24
+ end
25
+
26
+ def md5_string(s)
27
+ Digest::MD5.hexdigest(s.to_s)
28
+ end
29
+
30
+ def prompt?(question)
31
+ $stderr.write("#{question} (y/n) ")
32
+ $stderr.flush
33
+ $stdin.gets =~ /^y/i
34
+ end
35
+
36
+ def random_string(len)
37
+ (1..len).map { BASE_62.sample }.join
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,45 @@
1
+ module Scripto
2
+ module PrintCommands
3
+ RESET = "\e[0m"
4
+ GREEN = "\e[1;37;42m"
5
+ YELLOW = "\e[1;37;43m"
6
+ RED = "\e[1;37;41m"
7
+
8
+ attr_accessor :verbose
9
+
10
+ def verbose?
11
+ !!@verbose
12
+ end
13
+
14
+ def verbose!
15
+ @verbose = true
16
+ end
17
+
18
+ def vbanner(s = nil)
19
+ banner(s) if verbose?
20
+ end
21
+
22
+ def vputs(s = nil)
23
+ $stderr.puts(s) if verbose?
24
+ end
25
+
26
+ def vprintf(s, *args)
27
+ $stderr.printf(s, *args) if verbose?
28
+ end
29
+
30
+ def banner(s, color: GREEN)
31
+ now = Time.new.strftime("%H:%M:%S")
32
+ s = "#{s} ".ljust(72, " ")
33
+ $stderr.puts "#{color}[#{now}] #{s}#{RESET}"
34
+ end
35
+
36
+ def warning(msg)
37
+ banner("Warning: #{msg}", color: YELLOW)
38
+ end
39
+
40
+ def fatal(msg)
41
+ banner(msg, color: RED)
42
+ exit(1)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,86 @@
1
+ require "english"
2
+ require "shellwords"
3
+
4
+ module Scripto
5
+ module RunCommands
6
+ class Error < StandardError ; end
7
+
8
+ def run(command, args = nil)
9
+ cmd = CommandLine.new(command, args)
10
+ vputs(cmd)
11
+ cmd.run
12
+ end
13
+
14
+ def run_capture(command, args = nil)
15
+ CommandLine.new(command, args).capture
16
+ end
17
+
18
+ def run_quietly(command, args = nil)
19
+ cmd = CommandLine.new(command, args)
20
+ run("#{cmd} > /dev/null 2> /dev/null")
21
+ end
22
+
23
+ def run_succeeds?(command, args = nil)
24
+ begin
25
+ run_quietly(command, args)
26
+ true
27
+ rescue Error
28
+ false
29
+ end
30
+ end
31
+
32
+ def run_fails?(command, args = nil)
33
+ !run_succeeds?(command, args)
34
+ end
35
+
36
+ def shellescape(s)
37
+ Shellwords.escape(s)
38
+ end
39
+
40
+ protected
41
+
42
+ class CommandLine
43
+ attr_accessor :command, :args
44
+
45
+ def initialize(command, args)
46
+ self.command = command
47
+ self.args = if args
48
+ args.map(&:to_s)
49
+ else
50
+ [ ]
51
+ end
52
+ end
53
+
54
+ def run
55
+ system(command, *args)
56
+ raise!($CHILD_STATUS) if $CHILD_STATUS != 0
57
+ end
58
+
59
+ def capture
60
+ begin
61
+ captured = `#{to_s}`
62
+ rescue Errno::ENOENT
63
+ raise Error, "#{self} failed : ENOENT (No such file or directory)"
64
+ end
65
+ raise!($CHILD_STATUS) if $CHILD_STATUS != 0
66
+ captured
67
+ end
68
+
69
+ def raise!(status)
70
+ if status.termsig == Signal.list["INT"]
71
+ raise "#{self} interrupted"
72
+ end
73
+ raise Error, "#{self} failed : #{status.to_i / 256}"
74
+ end
75
+
76
+ def to_s
77
+ if args.length > 0
78
+ escaped = args.map { |i| Shellwords.escape(i) }
79
+ "#{command} #{escaped.join(" ")}"
80
+ else
81
+ command
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,3 @@
1
+ module Scripto
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'scripto/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "scripto"
8
+ spec.version = Scripto::VERSION
9
+ spec.platform = Gem::Platform::RUBY
10
+ spec.required_ruby_version = ">= 2.0.0"
11
+ spec.authors = ["Adam Doppelt"]
12
+ spec.email = ["amd@gurge.com"]
13
+ spec.summary = "Helpers for writing command line scripts."
14
+ spec.homepage = "http://github.com/gurgeous/scripto"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0")
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.5"
23
+ spec.add_development_dependency "minitest", "~> 5.0"
24
+ spec.add_development_dependency "rake"
25
+ end
@@ -0,0 +1,26 @@
1
+ require "fileutils"
2
+ require "minitest/autorun"
3
+ require "minitest/pride"
4
+
5
+ $LOAD_PATH << File.expand_path("../../lib", __FILE__)
6
+ require "scripto"
7
+
8
+ module Helper
9
+ TMP_DIR = "/tmp/_scripto_test"
10
+
11
+ # attr_accessor :main
12
+
13
+ def setup
14
+ # self.main = Scripto::Main.new
15
+ FileUtils.rm_rf(TMP_DIR)
16
+ FileUtils.mkdir_p(TMP_DIR)
17
+ @pwd = Dir.pwd
18
+ Dir.chdir(TMP_DIR)
19
+ Scripto.verbose = false
20
+ end
21
+
22
+ def teardown
23
+ FileUtils.rm_rf(TMP_DIR)
24
+ Dir.chdir(@pwd)
25
+ end
26
+ end
@@ -0,0 +1,60 @@
1
+ require_relative "helper"
2
+
3
+ class TestCsv < Minitest::Test
4
+ include Helper
5
+
6
+ FILE = "test.csv"
7
+
8
+ ROWS = [ { a: "1", b: "2", c: "3" }, { a: "4", b: "5", c: "6" } ]
9
+ ROWS_EXP = "a,b,c\n1,2,3\n4,5,6\n"
10
+ ROWS_REVERSED_EXP = "c,b,a\n3,2,1\n6,5,4\n"
11
+
12
+ def test_types
13
+ assert_equal(ROWS_EXP, Scripto.csv_to_s(ROWS))
14
+ assert_equal(ROWS_EXP, Scripto.csv_to_s(structs))
15
+ assert_equal(ROWS_EXP, Scripto.csv_to_s(ostructs))
16
+ end
17
+
18
+ def test_cols
19
+ assert_equal(ROWS_REVERSED_EXP, Scripto.csv_to_s(ROWS, cols: %i(c b a)))
20
+ assert_equal(ROWS_REVERSED_EXP, Scripto.csv_to_s(structs, cols: %i(c b a)))
21
+ assert_equal(ROWS_REVERSED_EXP, Scripto.csv_to_s(ostructs, cols: %i(c b a)))
22
+ end
23
+
24
+ def test_csv_stdout
25
+ assert_output(ROWS_EXP) { Scripto.csv_to_stdout(ROWS) }
26
+ end
27
+
28
+ def test_csv_read_write
29
+ Scripto.csv_write(FILE, ROWS)
30
+ assert_equal(ROWS_EXP, File.read(FILE))
31
+ assert_equal(ROWS, Scripto.csv_read(FILE).map(&:to_h))
32
+ end
33
+
34
+ def test_gz
35
+ Scripto.csv_write(FILE, ROWS)
36
+ Scripto.run("gzip #{FILE}")
37
+ assert_equal(ROWS, Scripto.csv_read("#{FILE}.gz").map(&:to_h))
38
+ end
39
+
40
+ def test_atomic
41
+ magic = "can't touch this"
42
+ File.write(FILE, magic)
43
+ begin
44
+ Util.csv_write(TMP, rows, cols: %i(bad_column))
45
+ rescue
46
+ end
47
+ assert_equal(magic, File.read(FILE))
48
+ end
49
+
50
+ protected
51
+
52
+ def structs
53
+ klass = Struct.new(*ROWS.first.keys)
54
+ ROWS.map { |i| klass.new(*i.values) }
55
+ end
56
+
57
+ def ostructs
58
+ ROWS.map { |i| OpenStruct.new(i) }
59
+ end
60
+ end
@@ -0,0 +1,200 @@
1
+ require_relative "helper"
2
+
3
+ class TestFile < Minitest::Test
4
+ include Helper
5
+
6
+ DIR = "dir"
7
+ SRC, DST = "src.txt", "dst.txt"
8
+ SRC2, DST2 = "src2.txt", "dst2.txt"
9
+
10
+ def setup
11
+ super
12
+ File.write(SRC, "something")
13
+ File.write(SRC2, "another thing")
14
+ end
15
+
16
+ #
17
+ # basics
18
+ #
19
+
20
+ def test_mkdir
21
+ Scripto.mkdir(DIR)
22
+ assert(File.directory?(DIR))
23
+ end
24
+
25
+ def test_mkdir_mode
26
+ Scripto.mkdir(DIR, mode: 0644)
27
+ assert_equal(0644, File.stat(DIR).mode & 0644)
28
+ end
29
+
30
+ def test_cp
31
+ Scripto.cp(SRC, DST)
32
+ assert_equal(File.read(SRC), File.read(DST))
33
+ end
34
+
35
+ def test_cp_mode
36
+ Scripto.cp(SRC, DST, mode: 0644)
37
+ assert_equal(0644, File.stat(DST).mode & 0644)
38
+ end
39
+
40
+ def test_cp_mkdir
41
+ in_dir = "#{DIR}/in_dir"
42
+ Scripto.cp(SRC, in_dir, mkdir: true)
43
+ assert_equal(File.read(SRC), File.read(in_dir))
44
+ end
45
+
46
+ def test_mv
47
+ Scripto.mv(SRC, DST)
48
+ assert_equal("something", File.read(DST))
49
+ end
50
+
51
+ def test_mv_mkdir
52
+ in_dir = "#{DIR}/in_dir"
53
+ Scripto.mv(SRC, in_dir, mkdir: true)
54
+ assert_equal("something", File.read(in_dir))
55
+ end
56
+
57
+ def test_ln
58
+ Scripto.ln(SRC, DST)
59
+ assert_equal(SRC, File.readlink(DST))
60
+ end
61
+
62
+ def test_rm
63
+ Scripto.rm(SRC)
64
+ assert(!File.exists?(SRC))
65
+ Scripto.rm("this_file_doesnt_exist") # shouldn't complain
66
+ end
67
+
68
+ #
69
+ # if necessary (this is useful for printing)
70
+ #
71
+
72
+ def test_if_necessary
73
+ # should return true
74
+ assert Scripto.mkdir_if_necessary(DIR)
75
+ assert Scripto.cp_if_necessary(SRC, DST)
76
+ assert Scripto.ln_if_necessary(SRC, DST2)
77
+
78
+ assert(File.directory?(DIR))
79
+ assert_equal(File.read(SRC), File.read(DST))
80
+ assert_equal(SRC, File.readlink(DST2))
81
+
82
+ # should be silent
83
+ assert_fu_output(nil, "") do
84
+ assert_nil Scripto.mkdir_if_necessary(DIR)
85
+ assert_nil Scripto.cp_if_necessary(SRC, DST)
86
+ assert_nil Scripto.ln_if_necessary(SRC, DST2)
87
+ end
88
+ end
89
+
90
+ def test_cp_if_necessary_differs
91
+ File.write(DST, "this is different")
92
+ assert_fu_output(nil, "cp -rp #{SRC} #{DST}\n") do
93
+ assert Scripto.cp_if_necessary(SRC, DST)
94
+ end
95
+ end
96
+
97
+ def test_ln_if_necessary_differs
98
+ File.symlink(SRC2, DST)
99
+ assert_fu_output(nil, "rm -f #{DST}\nln -sf #{SRC} #{DST}\n") do
100
+ assert Scripto.ln_if_necessary(SRC, DST)
101
+ assert_equal(SRC, File.readlink(DST))
102
+ end
103
+ end
104
+
105
+ def test_chmod
106
+ Scripto.chmod(SRC, 0644)
107
+ assert_equal(0644, File.stat(SRC).mode & 0644)
108
+ end
109
+
110
+ def test_rm_and_mkdir
111
+ Dir.mkdir(DIR)
112
+ File.write("#{DIR}/file", "this is a test")
113
+ assert Dir["#{DIR}/*"].length == 1
114
+ Scripto.rm_and_mkdir(DIR)
115
+ assert Dir["#{DIR}/*"].length == 0
116
+ end
117
+
118
+ def test_copy_metadata
119
+ File.chmod(0644, SRC)
120
+ File.utime(1234, 5678, SRC)
121
+ Scripto.copy_metadata(SRC, SRC2)
122
+ assert_equal(0644, File.stat(SRC2).mode & 0644)
123
+ assert_equal(1234, File.stat(SRC2).atime.to_i)
124
+ assert_equal(5678, File.stat(SRC2).mtime.to_i)
125
+ end
126
+
127
+ #
128
+ # chown rests - must be root
129
+ #
130
+
131
+ def test_mkdir_owner
132
+ skip if !root?
133
+ Scripto.mkdir(DIR, owner: "nobody")
134
+ assert(Etc.getpwnam("nobody").uid, File.stat(DIR).uid)
135
+ end
136
+
137
+ def test_cp_owner
138
+ skip if !root?
139
+ Scripto.cp(SRC, DST, owner: "nobody")
140
+ assert(Etc.getpwnam("nobody").uid, File.stat(DST).uid)
141
+ end
142
+
143
+ def test_chown
144
+ skip if !root?
145
+ Scripto.chown(SRC, "nobody")
146
+ assert(Etc.getpwnam("nobody").uid, File.stat(SRC).uid)
147
+ end
148
+
149
+ #
150
+ # verbosity
151
+ #
152
+
153
+ def test_mkdir_verbose
154
+ assert_fu_output(nil, "mkdir -p #{DIR}\n") do
155
+ Scripto.mkdir(DIR)
156
+ end
157
+ end
158
+
159
+ def test_cp_verbose
160
+ assert_fu_output(nil, "cp -rp #{SRC} #{DST}\n") do
161
+ Scripto.cp(SRC, DST)
162
+ end
163
+ end
164
+
165
+ def test_mv_verbose
166
+ assert_fu_output(nil, "mv #{SRC} #{DST}\n") do
167
+ Scripto.mv(SRC, DST)
168
+ end
169
+ end
170
+
171
+ def test_ln_verbose
172
+ assert_fu_output(nil, "ln -sf #{SRC} #{DST}\n") do
173
+ Scripto.ln(SRC, DST)
174
+ end
175
+ end
176
+
177
+ def test_rm_verbose
178
+ assert_fu_output(nil, "rm -f #{SRC}\n") do
179
+ Scripto.rm(SRC)
180
+ end
181
+ end
182
+
183
+ protected
184
+
185
+ def root?
186
+ if !defined?(@root)
187
+ @root = `whoami`.strip == "root"
188
+ end
189
+ @root
190
+ end
191
+
192
+ def assert_fu_output(stdout = nil, stderr = nil, &block)
193
+ Scripto.verbose!
194
+ assert_output(stdout, stderr) do
195
+ # FileUtils squirrels this away so we have to set it manually
196
+ FileUtils.instance_eval("@fileutils_output = $stderr")
197
+ yield
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,53 @@
1
+ require_relative "helper"
2
+
3
+ class TestMisc < Minitest::Test
4
+ include Helper
5
+
6
+ def test_whoami
7
+ assert_equal(`whoami`.strip, Scripto.whoami)
8
+ end
9
+
10
+ def test_root?
11
+ assert_equal(`whoami`.strip == "root", Scripto.root?)
12
+ end
13
+
14
+ def test_md5_string
15
+ assert_equal("ba73632f801ac2c72d78134722f2cb84", Scripto.md5_string("gub"))
16
+ end
17
+
18
+ def test_md5_file
19
+ File.write("test.txt", "gub")
20
+ assert_equal("ba73632f801ac2c72d78134722f2cb84", Scripto.md5_file("test.txt"))
21
+ end
22
+
23
+ def test_prompt?
24
+ with_fake_stdin("YES") do
25
+ assert_output(nil, "question (y/n) ") do
26
+ assert Scripto.prompt?("question")
27
+ end
28
+ end
29
+ with_fake_stdin("y") do
30
+ assert_output(nil, "question (y/n) ") do
31
+ assert Scripto.prompt?("question")
32
+ end
33
+ end
34
+ with_fake_stdin("no") do
35
+ assert_output(nil, "question (y/n) ") do
36
+ assert !Scripto.prompt?("question")
37
+ end
38
+ end
39
+ end
40
+
41
+ protected
42
+
43
+ def with_fake_stdin(str, &block)
44
+ old_stdin = $stdin
45
+ begin
46
+ $stdin = StringIO.new(str)
47
+ $stdin.rewind
48
+ yield
49
+ ensure
50
+ $stdin = old_stdin
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,28 @@
1
+ require_relative "helper"
2
+
3
+ class TestPrint < Minitest::Test
4
+ include Helper
5
+
6
+ def test_verbose?
7
+ assert(!Scripto.verbose?)
8
+ Scripto.verbose!
9
+ assert(Scripto.verbose?)
10
+ end
11
+
12
+ def test_quiet
13
+ assert_silent { Scripto.vbanner "gub" }
14
+ assert_silent { Scripto.vprintf "gub" }
15
+ assert_silent { Scripto.vputs "gub" }
16
+ end
17
+
18
+ def test_loud
19
+ Scripto.verbose!
20
+ assert_output(nil, /gub/) { Scripto.vbanner "gub" }
21
+ assert_output(nil, /gub/) { Scripto.vprintf "gub" }
22
+ assert_output(nil, /gub/) { Scripto.vputs "gub" }
23
+ end
24
+
25
+ def test_warning
26
+ assert_output(nil, /gub/) { Scripto.warning "gub" }
27
+ end
28
+ end
@@ -0,0 +1,103 @@
1
+ require_relative "helper"
2
+
3
+ class TestRun < Minitest::Test
4
+ include Helper
5
+
6
+ SUCCEEDS = "echo gub"
7
+ FAILS = "cat scripto_bogus_file 2> /dev/null"
8
+ BAD_COMMAND = "this_command_doesnt_exist"
9
+ SRC = "_scripto_src"
10
+ DST = "_scripto with spaces"
11
+ ARGS = [ "-f", SRC, DST ]
12
+
13
+ def setup
14
+ super
15
+ File.write(SRC, "something")
16
+ end
17
+
18
+ #
19
+ # basic methods
20
+ #
21
+
22
+ def test_run
23
+ Scripto.run("#{SUCCEEDS} > #{SRC}")
24
+ assert_equal("gub", File.read(SRC).strip)
25
+ assert("gub", Scripto.run_capture(SUCCEEDS))
26
+ Scripto.run_quietly(SUCCEEDS)
27
+ end
28
+
29
+ def test_run_succeeds?
30
+ assert_succeeds(SUCCEEDS)
31
+ assert_fails(FAILS)
32
+ assert_fails(BAD_COMMAND)
33
+ end
34
+
35
+ def test_shellescape
36
+ assert_equal("gub", Scripto.shellescape("gub"))
37
+ assert_equal("gub\\ zub", Scripto.shellescape("gub zub"))
38
+ end
39
+
40
+ # verbosity
41
+ def test_verbose
42
+ Scripto.verbose!
43
+ cmd = "#{SUCCEEDS} > /dev/null"
44
+ assert_output(nil, "#{cmd}\n") do
45
+ Scripto.run(cmd)
46
+ end
47
+ end
48
+
49
+ # commands that fail
50
+ def test_failures
51
+ assert_raises(Scripto::RunCommands::Error) { Scripto.run(BAD_COMMAND) }
52
+ assert_raises(Scripto::RunCommands::Error) { Scripto.run_capture(BAD_COMMAND) }
53
+ assert_raises(Scripto::RunCommands::Error) { Scripto.run(FAILS) }
54
+ assert_raises(Scripto::RunCommands::Error) { Scripto.run_capture(FAILS) }
55
+ end
56
+
57
+ #
58
+ # args
59
+ #
60
+
61
+ def test_run_args
62
+ # make sure SRC is copied to DST in all cases
63
+ assert_cp { Scripto.run("cp", ARGS) }
64
+ assert_cp { Scripto.run_quietly("cp", ARGS) }
65
+ assert_cp { assert_succeeds("cp", ARGS) }
66
+ end
67
+
68
+ def test_capture_escaping
69
+ tricky = "\"'!tricky!'\""
70
+ assert_equal("#{tricky} #{tricky}\n", Scripto.run_capture("echo", [tricky, tricky]))
71
+ end
72
+
73
+ def test_args_succeeds_fails
74
+ assert_fails(BAD_COMMAND, ARGS)
75
+ end
76
+
77
+ # is output escaped properly with verbose?
78
+ def test_args_verbose
79
+ Scripto.verbose!
80
+ assert_output(nil, "cp -f #{SRC} #{DST.gsub(" ", "\\ ")}\n") do
81
+ Scripto.run("cp", ARGS)
82
+ end
83
+ end
84
+
85
+ protected
86
+
87
+ def assert_cp(&block)
88
+ File.unlink(DST) if File.exists?(DST)
89
+ yield
90
+ assert_equal(File.read(SRC), File.read(DST))
91
+ File.unlink(DST)
92
+ end
93
+
94
+ def assert_succeeds(command, args = nil)
95
+ assert_equal(true, Scripto.run_succeeds?(command, args))
96
+ assert_equal(false, Scripto.run_fails?(command, args))
97
+ end
98
+
99
+ def assert_fails(command, args = nil)
100
+ assert_equal(false, Scripto.run_succeeds?(command, args))
101
+ assert_equal(true, Scripto.run_fails?(command, args))
102
+ end
103
+ end
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: scripto
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Adam Doppelt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description:
56
+ email:
57
+ - amd@gurge.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - lib/scripto.rb
68
+ - lib/scripto/csv_commands.rb
69
+ - lib/scripto/file_commands.rb
70
+ - lib/scripto/main.rb
71
+ - lib/scripto/misc_commands.rb
72
+ - lib/scripto/print_commands.rb
73
+ - lib/scripto/run_commands.rb
74
+ - lib/scripto/version.rb
75
+ - scripto.gemspec
76
+ - test/helper.rb
77
+ - test/test_csv.rb
78
+ - test/test_file.rb
79
+ - test/test_misc.rb
80
+ - test/test_print.rb
81
+ - test/test_run.rb
82
+ homepage: http://github.com/gurgeous/scripto
83
+ licenses:
84
+ - MIT
85
+ metadata: {}
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - '>='
93
+ - !ruby/object:Gem::Version
94
+ version: 2.0.0
95
+ required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ requirements: []
101
+ rubyforge_project:
102
+ rubygems_version: 2.2.1
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Helpers for writing command line scripts.
106
+ test_files:
107
+ - test/helper.rb
108
+ - test/test_csv.rb
109
+ - test/test_file.rb
110
+ - test/test_misc.rb
111
+ - test/test_print.rb
112
+ - test/test_run.rb