autoshell 1.0.0.pre.beta

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 928a9e9b3812a58ba5dc49d411c8d3aa8e1d8ca2
4
+ data.tar.gz: de0ace26b2252873a5c1ee7a211a39a2f31a356a
5
+ SHA512:
6
+ metadata.gz: b1f0cdea37569f2a28b18de0cb4c4bc67be9efb2e97defdc89c616a18c872aa2c25ddf7e2cb418049e8536d8d700d9b0709556c116c0207fe108f45ba28cc839
7
+ data.tar.gz: 3a009f5a35d003af45c22648b25eb5212529ea8eaaadd959212143fb0cdd5ddefa1a1613036dc770673b43a0975ebcf2383f24ae881172651211b79f77e62a86
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rubocop.yml ADDED
@@ -0,0 +1,30 @@
1
+ AllCops:
2
+ Include:
3
+ - '**/Rakefile'
4
+
5
+ #Style/HashSyntax:
6
+ #EnforcedStyle: hash_rockets
7
+
8
+ Style/GuardClause:
9
+ Enabled: false
10
+
11
+ Style/LineLength:
12
+ Max: 80
13
+
14
+ Style/NumericLiterals:
15
+ Enabled: false
16
+
17
+ Style/ClassAndModuleChildren:
18
+ Enabled: false
19
+
20
+ Style/SignalException:
21
+ EnforcedStyle: only_raise
22
+
23
+ Style/ClassLength:
24
+ Enabled: false
25
+
26
+ Style/MethodLength:
27
+ Enabled: false
28
+
29
+ Metrics/CyclomaticComplexity:
30
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.6
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in workdir.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Ryan Mark
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Autoshell
2
+
3
+ Simple wrapper for shell commands, used by [Autotune](https://github.com/voxmedia/autotune).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'autoshell', :github => 'ryanmark/autoshell-ruby'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ ## Usage
18
+
19
+ Create a new autoshell object with optional path and environment hash.
20
+
21
+ ```ruby
22
+ env = { 'FOO' => 'bar' }
23
+ sh = Autoshell.new('~/code/autoshell', env)
24
+ sh.clone('https://github.com/ryanmark/autoshell-ruby.git')
25
+ sh.setup_environment
26
+ sh.cd |s| { s.run('bundle', 'exec', 'rake', 'test') }
27
+ ```
28
+
29
+ ## Development
30
+
31
+ After checking out the repo, run `./setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `./console` for an interactive prompt that will allow you to experiment.
32
+
33
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
34
+
35
+ ## Contributing
36
+
37
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ryanmark/autoshell. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
38
+
39
+
40
+ ## License
41
+
42
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
43
+
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << 'test'
6
+ t.libs << 'lib'
7
+ t.test_files = FileList['test/*/test_*.rb']
8
+ end
9
+
10
+ task default: :test
data/autoshell.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'autoshell/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'autoshell'
8
+ spec.version = Autoshell::VERSION
9
+ spec.authors = ['Ryan Mark']
10
+ spec.email = ['ryan@mrk.cc']
11
+
12
+ spec.summary = 'Library for automating shell tasks in Autotune'
13
+ spec.description = ''
14
+ spec.homepage = 'http://github.com/ryanmark/autoshell'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`
18
+ .split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_runtime_dependency 'mime-types', '~> 2.6'
22
+ spec.add_runtime_dependency 'ansi', '~> 1.5'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.10'
25
+ spec.add_development_dependency 'rake', '~> 10.0'
26
+ spec.add_development_dependency 'yard'
27
+ spec.add_development_dependency 'minitest'
28
+ spec.add_development_dependency 'pry'
29
+ end
data/console ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'autoshell'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ require 'pry'
11
+ Pry.start
data/lib/autoshell.rb ADDED
@@ -0,0 +1,77 @@
1
+ require 'logger'
2
+
3
+ require 'autoshell/run'
4
+ require 'autoshell/environment'
5
+ require 'autoshell/filestuff'
6
+ require 'autoshell/git'
7
+ require 'autoshell/log'
8
+
9
+ # The top-level namespace of the Autoshell lib
10
+ #
11
+ #
12
+ module Autoshell
13
+ # These vars are copied from the ruby script's environment
14
+ ALLOWED_ENV = %w(PATH LANG USER LOGNAME LC_CTYPE LD_LIBRARY_PATH ARCHFLAGS
15
+ TMPDIR SSH_AUTH_SOCK HOME)
16
+
17
+ # Default log formatter
18
+ LOG_FORMATTER = proc { |_s, _d, _p, msg| msg }
19
+
20
+ # Default log level
21
+ LOG_LEVEL = Logger::DEBUG # WARN
22
+
23
+ # Exception thrown by autoshell methods when a command fails
24
+ #
25
+ # sh = Autoshell.new
26
+ # begin
27
+ # sh.run 'missing-command'
28
+ # rescue Autoshell::CommandError => exc
29
+ # puts 'command failed!'
30
+ # end
31
+ class CommandError < StandardError; end
32
+
33
+ class << self
34
+ # Create a new autoshell. Same as `Autoshell::Base.new`.
35
+ # @see Autoshell::Base#initialize
36
+ def new(path = '.', env: {}, logger: nil)
37
+ Base.new(path, env: env, logger: logger)
38
+ end
39
+ alias_method :open, :new
40
+ end
41
+
42
+ # The core autoshell class
43
+ # @!attribute env
44
+ # @return [Hash] environment variables in this shell
45
+ # @!attribute working_dir
46
+ # @return [String] current working directory of this shell
47
+ # @!attribute home_dir
48
+ # @return [String] directory this shell was started with
49
+ class Base
50
+ include Autoshell::Run
51
+ include Autoshell::Filestuff
52
+ include Autoshell::Environment
53
+ include Autoshell::Git
54
+ include Autoshell::Log
55
+
56
+ attr_accessor :env, :working_dir
57
+ alias_method :to_s, :working_dir
58
+
59
+ # Create a new shell object with a working directory and environment vars
60
+ #
61
+ # @param path [String] Create a new shell at this path
62
+ # @option env [Hash] :env Environment variables to add to this shell
63
+ # @option logger [Logger] :logger Logger instance to use
64
+ def initialize(path = '.', env: {}, logger: nil)
65
+ # save the working directory
66
+ self.working_dir = File.expand_path(path.to_s)
67
+ # Load whitelisted environment variables
68
+ self.env = ENV.select { |k, _| ALLOWED_ENV.include? k }
69
+ # Set some defaults
70
+ self.env['SHELL'] = '/bin/bash'
71
+ # Update environment variables from option
72
+ self.env.update env
73
+ # did we get a logger to use?
74
+ self.logger = logger if logger
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,63 @@
1
+ module Autoshell
2
+ # Stuff for working with a development environment
3
+ module Environment
4
+ # Is this a ruby project?
5
+ # @return [Boolean] true if this dir has a Gemfile
6
+ def ruby?
7
+ exist? 'Gemfile'
8
+ end
9
+
10
+ # Is this a python project?
11
+ # @return [Boolean] true if this dir has a requirements.txt
12
+ def python?
13
+ exist? 'requirements.txt'
14
+ end
15
+
16
+ # Is this a node project?
17
+ # @return [Boolean] true if this dir has a package.json
18
+ def node?
19
+ exist? 'package.json'
20
+ end
21
+
22
+ # Setup the environment
23
+ # @return [String] output of the environment setup commands
24
+ def setup_environment
25
+ setup_ruby_environment ||
26
+ setup_python_environment ||
27
+ setup_node_environment
28
+ end
29
+
30
+ # Do we have an environment setup?
31
+ # @return [Boolean] true if this dir has a bundle, virtualenv
32
+ # or node modules
33
+ def environment?
34
+ dir?('.bundle') || dir?('.virtualenv') || dir?('node_modules')
35
+ end
36
+
37
+ # Setup a ruby environment
38
+ # @return [String] output of the environment setup commands
39
+ def setup_ruby_environment
40
+ return unless ruby?
41
+ cd { run 'bundle', 'install', '--path', '.bundle', '--deployment' }
42
+ end
43
+
44
+ # Setup a python environment
45
+ # @return [String] output of the environment setup commands
46
+ def setup_python_environment
47
+ return unless python?
48
+ cd do
49
+ [
50
+ run('virtualenv', '.virtualenv'),
51
+ run('./.virtualenv/bin/pip', '-r', 'requirements.txt')
52
+ ].join("\n")
53
+ end
54
+ end
55
+
56
+ # Setup a node environment
57
+ # @return [String] output of the environment setup commands
58
+ def setup_node_environment
59
+ return unless node?
60
+ cd { run 'npm', 'install' }
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,180 @@
1
+ require 'fileutils'
2
+ require 'mime/types'
3
+ require 'json'
4
+
5
+ module Autoshell
6
+ module Filestuff
7
+ # expand a local path for this working directory
8
+ # @param path [String] local path to check
9
+ # @return [String] absolute path
10
+ def expand(path)
11
+ File.expand_path(path, working_dir)
12
+ end
13
+
14
+ # Check if the param exists on the system
15
+ # @param path [String] local path to check
16
+ # @return [Boolean]
17
+ def exist?(path = '.')
18
+ File.exist?(expand path)
19
+ end
20
+
21
+ # Check if the param is a directory
22
+ # @param path [String] local path to check
23
+ # @return [Boolean]
24
+ def dir?(path = '.')
25
+ Dir.exist?(expand path)
26
+ end
27
+
28
+ # Get matching files
29
+ # @param pattern [String] glob expression
30
+ # @return [Array] list of matching files
31
+ def glob(pattern)
32
+ cd { Dir.glob(pattern) }
33
+ end
34
+
35
+ # Delete a path in the working directory
36
+ # @param path [String] local file to delete
37
+ def rm(path = '.')
38
+ FileUtils.rm_rf(expand path)
39
+ end
40
+
41
+ # copy a path from the working directory to another location
42
+ # @param path [string] local file to copy
43
+ # @param dest [string] destination path to copy to
44
+ def cp(path, dest, force: false)
45
+ rm(dest) if force
46
+ raise CommandError, 'Destination exists' if exist?(dest)
47
+
48
+ mkpdir dest
49
+ FileUtils.cp_r(expand(path), expand(dest))
50
+ end
51
+
52
+ # Move something from the working directory to another location
53
+ # @param path [string] local file to move
54
+ # @param dest [string] destination path to move to
55
+ def mv(path, dest, force: false)
56
+ rm(dest) if force
57
+ raise CommandError, 'Destination exists' if exist?(dest)
58
+
59
+ mkpdir dest
60
+ FileUtils.mv(expand(path), expand(dest))
61
+ end
62
+
63
+ # Return an array of filenames
64
+ # @param path [String] path to list
65
+ # @return [Array<String>] all filenames in this directory
66
+ def ls(path = '.')
67
+ Dir.entries(expand path)
68
+ end
69
+
70
+ # Change directories
71
+ # @param path [String] path to work from
72
+ # @yieldreturn [self] this instance
73
+ # @return result of the block
74
+ def cd(path = nil)
75
+ unless path.nil?
76
+ original_dir = working_dir
77
+ @working_dir = expand(path)
78
+ end
79
+
80
+ unless Dir.exist? working_dir
81
+ raise CommandError,
82
+ "cd: The directory '#{working_dir}' does not exist"
83
+ end
84
+
85
+ ret = nil
86
+ Dir.chdir(working_dir) do
87
+ ret = yield self
88
+ end
89
+ @working_dir = original_dir unless path.nil?
90
+
91
+ ret # return
92
+ end
93
+
94
+ # Make all the parent directories for a path
95
+ # @param path [String] local dir path to create
96
+ def mkpdir(path = '.')
97
+ mkdir(File.dirname(expand path))
98
+ self
99
+ end
100
+
101
+ # Make all the directories for a path
102
+ # @param path [String] local dir path to create
103
+ def mkdir(path = '.')
104
+ FileUtils.mkdir_p(expand path)
105
+ self
106
+ end
107
+
108
+ # Move this working dir to another path
109
+ # @param path [String] destination path to move to
110
+ def move_to(path)
111
+ mv '.', path
112
+ self.home_dir = self.working_dir = expand path
113
+ self
114
+ end
115
+
116
+ # Copy this working dir to another path
117
+ # @param path [String] destination path to copy to
118
+ def copy_to(path = nil)
119
+ return super if path.nil?
120
+ cp '.', path
121
+ self.class.new(expand path)
122
+ end
123
+
124
+ # Get mime for a file
125
+ # @param path [String] local path of the file
126
+ # @return [String] mime type
127
+ def mime(path)
128
+ MIME::Types.type_for(expand path).first
129
+ end
130
+
131
+ # Read and parse a file
132
+ # @param path [String] local path of the file to read
133
+ # @return [String] contents of file at path
134
+ def read(path)
135
+ m = mime(path)
136
+ return read_text(path) unless m
137
+ return read_json(path) if m.content_type == 'application/json'
138
+ return read_yaml(path) if m.content_type == 'text/x-yaml'
139
+ return read_binary(path) if m.binary?
140
+ read_text(path)
141
+ end
142
+
143
+ # Read and parse JSON from a local path
144
+ # @param path [String] local path of the file to read
145
+ # @return contents of JSON
146
+ def read_json(path)
147
+ text = read_text(path)
148
+ return nil if text.nil?
149
+ JSON.parse(text)
150
+ rescue JSON::ParserError
151
+ nil
152
+ end
153
+
154
+ # Read and parse YAML from a local path
155
+ # @param path [String] local path of the file to read
156
+ # @return contents of YAML
157
+ def read_yaml(path)
158
+ require 'yaml'
159
+ text = read_text(path)
160
+ return nil if text.nil?
161
+ YAML.parse(text).to_h
162
+ rescue Psych::SyntaxError
163
+ nil
164
+ end
165
+
166
+ # return the contents of a local path
167
+ # @param path [String] local path of the file to read
168
+ # @return [String] text contents of path
169
+ def read_text(path)
170
+ File.read(expand path) if exist? path
171
+ end
172
+
173
+ # return the binary contents of a local path
174
+ # @param path [String] local path of the file to read
175
+ # @return [String] binary contents of path
176
+ def read_binary(path)
177
+ File.binread(expand path) if exist? path
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,78 @@
1
+ require 'fileutils'
2
+
3
+ module Autoshell
4
+ # Git repo stuff
5
+ # @!attribute branch
6
+ # @return [String] (master) branch of the current repo
7
+ module Git
8
+ def branch
9
+ @branch ||= git? ? git('rev-parse', '--abbrev-ref', 'HEAD') : 'master'
10
+ end
11
+ attr_writer :branch
12
+
13
+ # Has this repo been cloned to disk?
14
+ #
15
+ # @return [Boolean] True if this dir is a cloned repo
16
+ def git?
17
+ dir? '.git'
18
+ end
19
+
20
+ # Update the repo on disk
21
+ #
22
+ # @return [String] Output of git commands
23
+ def update
24
+ [
25
+ git('checkout', working_dir),
26
+ git('clean', '-fd'),
27
+ git('checkout', 'master'),
28
+ git('pull', '--recurse-submodules=yes'),
29
+ git('fetch', 'origin'),
30
+ git('checkout', branch),
31
+ git('submodule', 'update', '--init')
32
+ ].join("\n")
33
+ end
34
+
35
+ # Checkout a different branch
36
+ #
37
+ # @param [String] Branch name
38
+ # @return [String] Output of git commands
39
+ def switch(new_branch)
40
+ self.branch = new_branch
41
+ update
42
+ end
43
+
44
+ # Clone a repo to disk from the url
45
+ #
46
+ # @param [String] Git repository URL
47
+ # @return [String] Output of git commands
48
+ def clone(repo_url)
49
+ mkpdir working_dir
50
+ run 'git', 'clone', '--recursive', repo_url, working_dir
51
+ end
52
+
53
+ # Get the current commit hash
54
+ #
55
+ # @param [String] (HEAD) Branch or tag
56
+ # @return [String] Git commit hash
57
+ def commit_hash(branch_or_tag = nil)
58
+ @version = git 'rev-parse', branch_or_tag || 'HEAD'
59
+ end
60
+ alias_method :version, :commit_hash
61
+
62
+ # Get a tar archive of the repo as a string
63
+ #
64
+ # @param [String] (HEAD) Branch or tag
65
+ # @return [String] Zip-formatted binary string
66
+ def archive(branch_or_tag = nil)
67
+ git 'archive', branch_or_tag || 'HEAD', binmode: true
68
+ end
69
+
70
+ # Run a git command
71
+ #
72
+ # @param [*Array<String>] Command
73
+ # @return [String] Command output
74
+ def git(*args)
75
+ cd { run(*['git'] + args) }
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,45 @@
1
+ require 'logger'
2
+ require 'stringio'
3
+ require 'ansi/code'
4
+
5
+ module Autoshell
6
+ # Mixin for handling log stuff
7
+ module Log
8
+ # Instance-specific logger
9
+ #
10
+ # shell = Autoshell.new '~/test'
11
+ # shell.logger
12
+ #
13
+ # shell.logger = Rails.logger
14
+ #
15
+ # @return [Logger] logger instance
16
+ def logger
17
+ return @logger if @logger
18
+
19
+ @log_device = StringIO.new
20
+ @logger = Logger.new(@log_device)
21
+ @logger.level = LOG_LEVEL
22
+ @logger.formatter = LOG_FORMATTER
23
+ @logger
24
+ end
25
+ attr_writer :logger
26
+
27
+ # Get the complete output of the log
28
+ # @return [String] log contents
29
+ def log_output(color: false)
30
+ return unless @log_device
31
+ if color
32
+ @log_device.string
33
+ else
34
+ ANSI.unansi(@log_device.string)
35
+ end
36
+ end
37
+
38
+ # Reset the log contents
39
+ # @return self
40
+ def log_reset
41
+ @log_device.truncate(0) if @log_device
42
+ self
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,65 @@
1
+ require 'ansi/code'
2
+ require 'open3'
3
+
4
+ module Autoshell
5
+ # Execution stuff
6
+ module Run
7
+ # Wrapper around Open3.capture2e
8
+ #
9
+ # @see Open3#capture2e
10
+ # @return [String] command output
11
+ # @raise [CommandError] if the command fails
12
+ def run(*args, **opts)
13
+ # reset all environment variables...
14
+ opts[:unsetenv_others] = true unless opts.keys.include? :unsetenv_others
15
+
16
+ # run the command
17
+ out, status = Open3.capture2e(@env, *args, **opts)
18
+
19
+ # cleanup output
20
+ out.strip!
21
+
22
+ # the prompt
23
+ msg = "#{prompt_ansi(args)}\n#{out}"
24
+
25
+ if status.success?
26
+ logger.debug msg
27
+ return out
28
+ else
29
+ logger.error msg
30
+ raise CommandError, "#{prompt_text(args)}\n#{out}"
31
+ end
32
+ end
33
+
34
+ # Check if a command is available
35
+ #
36
+ # @param cmd [String] Name of the command
37
+ # @return [String] Path to the command
38
+ # @return [False] If command does not exist
39
+ def command?(cmd)
40
+ run('which', cmd.to_s)
41
+ rescue CommandError
42
+ return false
43
+ end
44
+
45
+ private
46
+
47
+ # Render a prompt string for logging
48
+ #
49
+ # @private
50
+ # @param cmd [Array<String>] array of command parts
51
+ # @return [String] ansi formatted string
52
+ def prompt_ansi(cmd)
53
+ "#{ANSI.blue(working_dir)} $ #{ANSI.white(cmd.join(' '))}"
54
+ end
55
+
56
+ # Render a prompt string for logging
57
+ #
58
+ # @private
59
+ # @param cmd [Array<String>] array of command parts
60
+ # @return [String] plain text string
61
+ def prompt_text(cmd)
62
+ ANSI.unansi(prompt_ansi(cmd))
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,50 @@
1
+ require 'autoshell'
2
+ require 'fileutils'
3
+
4
+ module Autoshell
5
+ # Helper test class
6
+ module TestHelper
7
+ REPO_URL = File.expand_path(
8
+ '../../../test/fixtures/autotune-example-blueprint.git', __FILE__)
9
+ FIXTURES_PATH = File.expand_path('../../../test/fixtures', __FILE__)
10
+
11
+ def before_setup
12
+ @dirs = {}
13
+ @fixtures = {}
14
+ end
15
+
16
+ def after_teardown
17
+ @dirs.values.each do |dir|
18
+ FileUtils.rm_rf(dir) if File.exist?(dir)
19
+ end
20
+ end
21
+
22
+ # Get a temp dir that will get cleaned-up after this test
23
+ # @param name [Symbol] name name of the tmpdir to get
24
+ # @return [Pathname] absolute path
25
+ def dir(name = :test)
26
+ @dirs[name.to_sym] ||= Pathname.new(
27
+ File.expand_path("#{Dir.tmpdir}/#{Time.now.to_i}#{rand(1000)}/"))
28
+ end
29
+
30
+ # autoshell fixture retriever
31
+ #
32
+ # @param name [Symbol] name of the fixture to retrieve
33
+ # @return [Autoshell::Base]
34
+ def autoshell(name)
35
+ @fixtures[name.to_sym] ||= begin
36
+ tmpdir = dir(name)
37
+ dest_path = tmpdir.join(name.to_s)
38
+
39
+ # if there is a matching dir in fixtures, copy it to the temp dir
40
+ fixtures_path = File.join(FIXTURES_PATH, name.to_s)
41
+ if Dir.exist? fixtures_path
42
+ FileUtils.mkdir_p(tmpdir)
43
+ FileUtils.cp_r(fixtures_path, dest_path)
44
+ end
45
+
46
+ Autoshell.new(dest_path)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,4 @@
1
+ # Version info
2
+ module Autoshell
3
+ VERSION = '1.0.0-beta'
4
+ end
data/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: autoshell
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.pre.beta
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Mark
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mime-types
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: ansi
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.10'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: ''
112
+ email:
113
+ - ryan@mrk.cc
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".rubocop.yml"
120
+ - ".travis.yml"
121
+ - CODE_OF_CONDUCT.md
122
+ - Gemfile
123
+ - LICENSE.txt
124
+ - README.md
125
+ - Rakefile
126
+ - autoshell.gemspec
127
+ - console
128
+ - lib/autoshell.rb
129
+ - lib/autoshell/environment.rb
130
+ - lib/autoshell/filestuff.rb
131
+ - lib/autoshell/git.rb
132
+ - lib/autoshell/log.rb
133
+ - lib/autoshell/run.rb
134
+ - lib/autoshell/test_helper.rb
135
+ - lib/autoshell/version.rb
136
+ - setup
137
+ homepage: http://github.com/ryanmark/autoshell
138
+ licenses:
139
+ - MIT
140
+ metadata: {}
141
+ post_install_message:
142
+ rdoc_options: []
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - ">"
153
+ - !ruby/object:Gem::Version
154
+ version: 1.3.1
155
+ requirements: []
156
+ rubyforge_project:
157
+ rubygems_version: 2.4.5
158
+ signing_key:
159
+ specification_version: 4
160
+ summary: Library for automating shell tasks in Autotune
161
+ test_files: []