mnogootex 0.2.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/main.yml +41 -0
  3. data/.gitignore +3 -0
  4. data/.rspec +0 -2
  5. data/.rubocop.yml +13 -0
  6. data/CODE_OF_CONDUCT.md +1 -1
  7. data/Gemfile +4 -3
  8. data/Guardfile +56 -0
  9. data/README.md +163 -17
  10. data/Rakefile +25 -4
  11. data/exe/mnogootex +2 -92
  12. data/lib/mnogootex/cfg.rb +62 -0
  13. data/lib/mnogootex/cli.rb +80 -0
  14. data/lib/mnogootex/core_ext.rb +11 -0
  15. data/lib/mnogootex/defaults.yml +7 -0
  16. data/lib/mnogootex/job/logger.rb +53 -0
  17. data/lib/mnogootex/job/porter.rb +53 -0
  18. data/lib/mnogootex/job/runner.rb +43 -0
  19. data/lib/mnogootex/job/warden.rb +100 -0
  20. data/lib/mnogootex/log/level.rb +17 -0
  21. data/lib/mnogootex/log/levels.yml +29 -0
  22. data/lib/mnogootex/log/line.rb +14 -0
  23. data/lib/mnogootex/log/matcher.rb +17 -0
  24. data/lib/mnogootex/log/matchers.yml +205 -0
  25. data/lib/mnogootex/log/processor.rb +115 -0
  26. data/lib/mnogootex/log.rb +23 -0
  27. data/lib/mnogootex/mnogoo.sh +21 -0
  28. data/lib/mnogootex/utils.rb +27 -0
  29. data/lib/mnogootex/version.rb +3 -1
  30. data/lib/mnogootex.rb +4 -4
  31. data/mnogootex.gemspec +43 -18
  32. data/spec/mnogootex/cfg_spec.rb +54 -0
  33. data/spec/mnogootex/job/porter_spec.rb +140 -0
  34. data/spec/mnogootex/job/runner_spec.rb +74 -0
  35. data/spec/mnogootex/log/processor_spec.rb +203 -0
  36. data/spec/mnogootex/utils_spec.rb +52 -0
  37. data/spec/spec_helper.rb +124 -0
  38. data/tty.gif +0 -0
  39. metadata +148 -29
  40. data/.gitmodules +0 -3
  41. data/.travis.yml +0 -5
  42. data/bin/console +0 -14
  43. data/bin/setup +0 -8
  44. data/lib/mnogootex/configuration.rb +0 -46
  45. data/lib/mnogootex/job.rb +0 -75
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f84bc4403ed2b6c0cf0ced691e4ebf69449de8fb
4
- data.tar.gz: 826c773e078eb685b7dacfa0b7c9936a07b5c29c
2
+ SHA256:
3
+ metadata.gz: 654469a2719e7a34e16be659b3b59cbf8611f1f5025ccba19ba1bea60e35d87b
4
+ data.tar.gz: cc026af91f6270d36fd5affa76565e49ba781638965cb0b377c8775d84cbc8fb
5
5
  SHA512:
6
- metadata.gz: 5dd132fa97940367f3aab6b6ef9a284ab5bb7164adb5b7c20f6aaeaa791218f13d33af0529fcb5809f37755e434d09eda3938488a083f0706c7f33b6642d7e77
7
- data.tar.gz: 81aecc276bc9a5f880bb5b92043859c0e130ec5b07b5caa0b1190b1f1cafef75e531f4271bd59d2a40475cd41169a8d42363dfdc681df73b45bcd1a5c4df5e29
6
+ metadata.gz: 2cf80aa5a52753bfec92a5ce7a6ff1c0a1d3d84376fdc897ed364097b52126245e5852284b474e81adee288c30d316753cb0bd38b8d75fbf541345512c834754
7
+ data.tar.gz: a71bda28d8eded4790cb3b40b6b673c58e3f96e630e42bb512c80afd004f869f559938ff83c7fb358780f59007c4117cad5bd0cf0b20e9d956c9c1d81425cfac
@@ -0,0 +1,41 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ main:
9
+ name: >-
10
+ ${{ matrix.os }} ${{ matrix.ruby }}
11
+ runs-on: ${{ matrix.os }}-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [ ubuntu, macos ]
16
+ ruby: [ '2.6', '2.7', '3.0' ]
17
+
18
+ steps:
19
+
20
+ - name: Checkout repo
21
+ uses: actions/checkout@v2
22
+
23
+ - name: Set up Ruby
24
+ uses: ruby/setup-ruby@v1
25
+ with:
26
+ ruby-version: ${{ matrix.ruby }}
27
+
28
+ - name: Cache Ruby gems
29
+ uses: actions/cache@v2
30
+ with:
31
+ path: vendor/bundle
32
+ key: gems-${{ matrix.os }}-${{ matrix.ruby }}-${{ hashFiles('Gemfile', 'mnogootex.gemspec') }}
33
+ restore-keys: gems-${{ matrix.os }}-${{ matrix.ruby }}-
34
+
35
+ - name: Install Ruby gems
36
+ run: |
37
+ bundle config path vendor/bundle
38
+ bundle install --jobs 3 --retry 3
39
+
40
+ - name: Run tests
41
+ run: bundle exec rake spec:rspec
data/.gitignore CHANGED
@@ -51,3 +51,6 @@ Gemfile.lock
51
51
 
52
52
  # rspec failure tracking
53
53
  .rspec_status
54
+
55
+ # byebug history
56
+ **/.byebug_history
data/.rspec CHANGED
@@ -1,3 +1 @@
1
- --format documentation
2
- --color
3
1
  --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.6
3
+ NewCops: enable
4
+ Metrics/LineLength:
5
+ Max: 120
6
+ Layout/DotPosition:
7
+ EnforcedStyle: trailing
8
+ Metrics/BlockLength:
9
+ Exclude:
10
+ - spec/**/*_spec.rb
11
+ # TODO: re-enable
12
+ Style/Documentation:
13
+ Enabled: false
data/CODE_OF_CONDUCT.md CHANGED
@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
55
55
  ## Enforcement
56
56
 
57
57
  Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at TODO: Write your email address. All
58
+ reported by contacting the project team at <paolo.brasolin@gmail.com>. All
59
59
  complaints will be reviewed and investigated and will result in a response that
60
60
  is deemed necessary and appropriate to the circumstances. The project team is
61
61
  obligated to maintain confidentiality with regard to the reporter of an incident.
data/Gemfile CHANGED
@@ -1,6 +1,7 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
6
 
5
- # Specify your gem's dependencies in mnogootex.gemspec
6
7
  gemspec
data/Guardfile ADDED
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ guard :rspec, cmd: 'bundle exec rspec' do
4
+ require 'guard/rspec/dsl'
5
+ dsl = Guard::RSpec::Dsl.new(self)
6
+
7
+ # RSpec files
8
+ watch(dsl.rspec.spec_helper) { dsl.rspec.spec_dir }
9
+ watch(dsl.rspec.spec_files)
10
+
11
+ # Ruby files
12
+ dsl.watch_spec_files_for(dsl.ruby.lib_files)
13
+ end
14
+
15
+ # # TODO: refactor the following into a new version of guard-mutant
16
+
17
+ # require 'mutant'
18
+ # require 'dry/inflector'
19
+ # require 'guard/compat/plugin'
20
+
21
+ # # NOTE: :: is mandatory for inline guards
22
+ # module ::Guard
23
+ # class Mutant < Plugin
24
+ # def initialize(options = {})
25
+ # opts = options.dup
26
+ # # @my_option = opts.delete(:my_special_option)
27
+ # super(opts) # important to call + avoid passing options Guard doesn't understand
28
+ # end
29
+
30
+ # # TODO: how would this make sense?
31
+ # # def run_all; end
32
+
33
+ # def run_on_modifications(paths)
34
+ # inflector = Dry::Inflector.new
35
+ # subjects = paths.map do |path|
36
+ # match = path.match(%r{(?:spec|lib)\/(.*?)(?:_spec)?.rb}).captures.first
37
+ # inflector.camelize match
38
+ # end
39
+ # succesful = ::Mutant::CLI.run(%w[--use rspec --fail-fast] + subjects)
40
+ # throw :task_has_failed unless succesful
41
+ # self
42
+ # end
43
+ # end
44
+ # end
45
+
46
+ # guard :mutant do
47
+ # require 'guard/rspec/dsl'
48
+ # dsl = Guard::RSpec::Dsl.new(self)
49
+
50
+ # # RSpec files
51
+ # # watch(dsl.rspec.spec_helper) { dsl.rspec.spec_dir }
52
+ # watch(dsl.rspec.spec_files)
53
+
54
+ # # Ruby files
55
+ # dsl.watch_spec_files_for(dsl.ruby.lib_files)
56
+ # end
data/README.md CHANGED
@@ -1,38 +1,184 @@
1
1
  # Многоꙮтех
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/mnogootex`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ [![Build Status](https://travis-ci.org/paolobrasolin/mnogootex.svg?branch=master)](https://travis-ci.org/paolobrasolin/mnogootex)
4
+ [![Gem Version](https://badge.fury.io/rb/mnogootex.svg)](https://badge.fury.io/rb/mnogootex)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![Code Climate](https://codeclimate.com/github/paolobrasolin/mnogootex/badges/gpa.svg)](https://codeclimate.com/github/paolobrasolin/mnogootex)
7
+ <!-- [![Test Coverage](https://codeclimate.com/github/paolobrasolin/mnogootex/badges/coverage.svg)](https://codeclimate.com/github/paolobrasolin/mnogootex/coverage) -->
8
+ <!-- [![Inline docs](http://inch-ci.org/github/paolobrasolin/mnogootex.svg?branch=master)](http://inch-ci.org/github/paolobrasolin/mnogootex) -->
9
+ <!-- [![Issue Count](https://codeclimate.com/github/paolobrasolin/mnogootex/badges/issue_count.svg)](https://codeclimate.com/github/paolobrasolin/mnogootex) -->
10
+
11
+ Многоꙮтех (mnogootex) is a utility that parallelizes compilation
12
+ of a LaTeX document using different classes and offers a
13
+ meaningfully filtered output.
14
+
15
+ The motivating use case is maintaining a single preamble while
16
+ submitting a paper to many journals using their outdated or crummy
17
+ document classes.
6
18
 
7
19
  ## Installation
8
20
 
9
- Add this line to your application's Gemfile:
21
+ The only requirement is [Ruby](https://www.ruby-lang.org) (>=2.5 as earlier versions are untested).
22
+
23
+ To install многоꙮтех execute
24
+
25
+ gem install mnogootex
26
+
27
+ To install `mnogoo` (strongly recommended shell integration) add this to your shell profile
10
28
 
11
- ```ruby
12
- gem 'mnogootex'
13
- ```
29
+ [ -s "$(mnogootex mnogoo)" ] && . "$(mnogootex mnogoo)"
14
30
 
15
- And then execute:
31
+ ## Quick start
16
32
 
17
- $ bundle
33
+ Set up your `LaTeX` project as usual - let's say its main file is `~/project/main.tex` and contains `\documentclass{...}`.
18
34
 
19
- Or install it yourself as:
35
+ Create a configuration file `~/project/.mnogootex.yml`
36
+ containing the list of document classes you want to compile your
37
+ project against:
20
38
 
21
- $ gem install mnogootex
39
+ jobs:
40
+ - scrartcl
41
+ - article
42
+ - book
43
+
44
+ Run `mnogootex go ~/project/main.tex` and enjoy the technicolor:
45
+
46
+ ![Demo TTY GIF](tty.gif?raw=true "Demo TTY GIF")
22
47
 
23
48
  ## Usage
24
49
 
25
- TODO: Write usage instructions here
50
+ In essence, Многоꙮтех
51
+ 1. takes the _source_ directory of a project,
52
+ 2. clones it into _target_ directories (one for each _job_),
53
+ 3. applies a different source code transformation to each one and then
54
+ 4. attempts to compile them.
55
+
56
+ Its convenience lies in the fact that it
57
+ * automates the setup process,
58
+ * parallelizes compilation,
59
+ * filters and colour codes the infamous waterfall logs and
60
+ * allows you to easily navigate through targets/source folders.
61
+
62
+ Многоꙮтех can be invoked from commandline in two ways: `mnogootex` and `mnogoo`.
63
+ The latter is more powerful and requires an extra [installation](#installation) step.
64
+
65
+ Commands listed below can be passed to both unless otherwise stated.
66
+
67
+ ### Commands
68
+
69
+ > **NOTATION:** `[FOO]` means that _`FOO` is optional_ while `FOO ...` means _one or more `FOO`s_.
70
+
71
+ #### `help [COMMAND]`
72
+
73
+ Prints the help for `COMMAND` (or all commands if none is given).
74
+
75
+ #### `mnogoo`
76
+
77
+ Prints the location of the `mnogoo` shell integration script.
78
+ Useful only for its [installation](#installation).
79
+
80
+ #### `go [JOB ...] [MAIN]`
81
+
82
+ Run given compilation `JOB`s for the `MAIN` document.
83
+
84
+ If no `JOB` list is given then all of them are run.
85
+ They are deduced from the [configuration](#configuration).
86
+
87
+ If no `MAIN` document is given then it's deduced from either
88
+ your current working directory or the [configuration](#configuration).
89
+
90
+ #### `dir [JOB] [MAIN]`
91
+
92
+ Print `JOB`'s temporary directory for the `MAIN` document.
93
+
94
+ If no `JOB` is given then it prints the source directory.
95
+
96
+ If no `MAIN` document is given then it's deduced from either
97
+ your current working directory or the [configuration](#configuration).
98
+
99
+ #### `cd [JOB] [MAIN]`
100
+
101
+ > **NOTE:** recognized by `mnogoo` only.
102
+
103
+ Checks into `JOB`'s temporary directory for the `MAIN` document.
104
+
105
+ If no `JOB` is given then it checks into the source directory.
106
+
107
+ If no `MAIN` document is given then it's deduced from either
108
+ your current working directory or the [configuration](#configuration).
109
+
110
+ #### `clobber`
111
+
112
+ Deletes all temporary files.
113
+ Useful to free up some space from time to time.
114
+
115
+ #### `pdf [JOB ...] [MAIN]`
116
+
117
+ Print `JOB`'s output PDF path for the `MAIN` document.
118
+
119
+ If no `JOB` list is given then all their output PDFs paths are printed.
120
+ They are deduced from the [configuration](#configuration).
121
+
122
+ If no `MAIN` document is given then it's deduced from either
123
+ your current working directory or the [configuration](#configuration).
124
+
125
+ #### `open [JOB ...] [MAIN]`
126
+
127
+ > **NOTE:** recognized by `mnogoo` only.
128
+
129
+ Open `JOB`'s output PDF for the `MAIN` document with your default viewer.
130
+
131
+ If no `JOB` list is given then all their output PDFs are opened.
132
+ They are deduced from the [configuration](#configuration).
133
+
134
+ If no `MAIN` document is given then it's deduced from either
135
+ your current working directory or the [configuration](#configuration).
136
+
137
+ ### Configuration
138
+
139
+ Многоꙮтех is configured through [`YAML`](https://learnxinyminutes.com/docs/yaml/)
140
+ files named `.mnogootex.yml` put into your projects' root directory.
141
+
142
+ When loads a configuration it also looks up for `.mnogootex.yml`
143
+ files in all parent directories to merge then together (from the
144
+ shallowest to the deepest path). This means that e.g. you can keep
145
+ a configuration file in your home folder and use it as a global
146
+ configuration for all you projects, while overwriting only specific
147
+ options in the configuration files of each one.
148
+
149
+ Многоꙮтех currently accepts three options.
150
+
151
+ #### `spinner`
152
+
153
+ This option is a string whose characters are the frames used to
154
+ animate the spinners for the command line interface.
155
+
156
+ # Default value:
157
+ spinner: ⣾⣽⣻⢿⡿⣟⣯⣷
158
+
159
+ #### `commandline`
160
+
161
+ This option is an array of the components for the commandline used
162
+ to compile documents.
163
+
164
+ # Default value:
165
+ commandline:
166
+ - latexmk
167
+ - -pdf
168
+ - --interaction=nonstopmode
169
+
170
+ #### `work_path`
26
171
 
27
- ## Development
172
+ This option is an override for the path where compilation happens.
28
173
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
174
+ # Default value:
175
+ work_path: null
30
176
 
31
- 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).
177
+ By default each run happens in a new empty folder. Overriding this allows you to easily reach the compilation artifacts, but leaves handling cleanup and conflicts with previous runs up to you.
32
178
 
33
179
  ## Contributing
34
180
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/mnogootex. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
181
+ Bug reports and pull requests are welcome on GitHub at https://github.com/paolobrasolin/mnogootex. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
36
182
 
37
183
  ## License
38
184
 
@@ -40,4 +186,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
40
186
 
41
187
  ## Code of Conduct
42
188
 
43
- Everyone interacting in the Mnogootex project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/mnogootex/blob/master/CODE_OF_CONDUCT.md).
189
+ Everyone interacting in the многоꙮтех project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/paolobrasolin/mnogootex/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile CHANGED
@@ -1,6 +1,27 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ # frozen_string_literal: true
3
2
 
4
- RSpec::Core::RakeTask.new(:spec)
3
+ # require 'mutant'
4
+ # require 'dry/inflector'
5
5
 
6
- task :default => :spec
6
+ require 'rspec/core/rake_task'
7
+
8
+ namespace :spec do
9
+ desc 'run RSpec'
10
+ RSpec::Core::RakeTask.new(:rspec) do |task|
11
+ task.rspec_opts = '--format documentation'
12
+ end
13
+
14
+ desc 'run SimpleCov'
15
+ task :simplecov do
16
+ ENV['COVERAGE'] = 'true'
17
+ Rake::Task['spec:rspec'].invoke
18
+ end
19
+
20
+ # desc 'run Mutant'
21
+ # task :mutant, [:subject] do |_, args|
22
+ # subjects = [args[:subject]].compact
23
+ # subjects << 'Mnogootex*' if subjects.empty?
24
+ # successful = ::Mutant::CLI.run(%w[--use rspec --fail-fast] + subjects)
25
+ # raise('Mutant task is not successful') unless successful
26
+ # end
27
+ end
data/exe/mnogootex CHANGED
@@ -1,96 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
- # coding: utf-8
2
+ # frozen_string_literal: true
3
3
 
4
4
  require 'mnogootex'
5
5
 
6
-
7
- # require 'pathname'
8
-
9
- # target = ARGV[0]
10
- # target_path = File.expand_path target
11
- # cfg = Mnogootex::Configuration.new
12
- # cfg.load target_path
13
-
14
- require 'tmpdir'
15
- require 'fileutils'
16
- require 'open3'
17
-
18
- require 'colorize'
19
-
20
- target = ARGV[0]
21
-
22
-
23
- raise "No parameters given." if ARGV.length.zero?
24
-
25
- if ARGV.length == 3
26
- raise "Unknown command." unless %w{show view open}.include? ARGV[1].downcase
27
- job = Mnogootex::Job.new cls: ARGV[2], target: File.expand_path(target)
28
- pdf = Dir.glob("#{job.tmp_dirname}/*.pdf").first
29
- raise "PDF non esiste." unless File.exist? pdf
30
- `open #{pdf}`
31
- exit
32
- end
33
-
34
- puts "Mnogootex v#{Mnogootex::VERSION}"
35
-
36
- main_path = File.expand_path(target)
37
- main_basename = File.basename main_path
38
- main_dirname = File.dirname main_path
39
-
40
- cfg = Mnogootex::Configuration.new
41
- cfg.load main_dirname
42
-
43
- raise "File non esiste." unless File.exist? main_path
44
-
45
- @documentclasses = cfg['compile_with']
46
-
47
- $jobs = []
48
- $threads = []
49
- $draw_threads = []
50
-
51
- $threads = []
52
-
53
- $anim = cfg['animation'].freeze
54
-
55
- STDOUT.sync = true
56
-
57
- def draw_status
58
- icons = $jobs.map do |j|
59
- icon = $anim[j.ticks % $anim.length]
60
- case j.thread.status
61
- when 'sleep', 'run', 'aborting'
62
- icon.yellow
63
- when false, nil # exited (normally or w/ error)
64
- j.success? ? icon.green : icon.red
65
- end
66
- end
67
- print ' Jobs: ' + icons.join + "\r"
68
- end
69
-
70
- draw_status
71
-
72
- @documentclasses.each_with_index do |cls, index|
73
- job = Mnogootex::Job.new cls: cls, target: main_path
74
- job.setup
75
- job.run
76
-
77
- $jobs << job
78
-
79
- $draw_threads << job.tick_thread
80
- $threads << job.thread
81
- end
82
-
83
- $threads.map(&:join)
84
- $draw_threads.map(&:join)
85
-
86
- puts
87
-
88
- puts ' Details:'
89
- $jobs.each do |job|
90
- if job.success?
91
- puts ' ' + "✔".green + ' ' + File.basename(job.cls)
92
- else
93
- puts ' ' + "✘".red + ' ' + File.basename(job.cls)
94
- puts job.log[2..-2].join.gsub(/^/,' '*6).chomp.red
95
- end
96
- end
6
+ Mnogootex::CLI.start ARGV
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require 'pathname'
5
+
6
+ require 'mnogootex/core_ext'
7
+
8
+ module Mnogootex
9
+ module Cfg
10
+ BASENAME = '.mnogootex.yml'
11
+ DEFAULTS = YAML.load_file(Pathname.new(__dir__).join('defaults.yml'))
12
+
13
+ def self.load_descending(pathname:, basename:)
14
+ pathname.realpath.descend.
15
+ map { |path| path.join(basename) }.
16
+ select(&:exist?).reject(&:zero?).
17
+ map { |path| YAML.load_file(path) }.
18
+ reduce(&:merge!)
19
+ end
20
+
21
+ def self.recombobulate(*args)
22
+ try_args(*args) || try_link(*args) || try_cfgs(*args)
23
+ end
24
+
25
+ class << self
26
+ private
27
+
28
+ def try_args(*args)
29
+ main = Pathname.new(args.fetch(-1, ''))
30
+ return unless main.file?
31
+
32
+ main = main.realpath
33
+ cfg = load_descending(pathname: main.dirname, basename: BASENAME)
34
+ jobs = args[0..-2].unless(&:empty?)
35
+
36
+ [jobs, main, cfg]
37
+ end
38
+
39
+ def try_link(*args)
40
+ link = Pathname.pwd.ascend.map { |p| p.join('.mnogootex.src') }.detect(&:symlink?)
41
+ return if link.nil?
42
+
43
+ main = link.readlink.realpath
44
+ cfg = load_descending(pathname: main.dirname, basename: BASENAME)
45
+ jobs = args
46
+
47
+ [jobs, main, cfg]
48
+ end
49
+
50
+ def try_cfgs(*args)
51
+ yaml = Pathname.pwd.ascend.map { |p| p.join('.mnogootex.yml') }.detect(&:file?)
52
+ return if yaml.nil?
53
+
54
+ cfg = load_descending(pathname: yaml.dirname, basename: BASENAME)
55
+ main = yaml.dirname.join(cfg.fetch('main', '')).if(&:file?)&.realpath
56
+ jobs = args
57
+
58
+ [jobs, main, cfg]
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require 'pathname'
5
+
6
+ require 'mnogootex/utils'
7
+ require 'mnogootex/job/warden'
8
+ require 'mnogootex/job/porter'
9
+ require 'mnogootex/cfg'
10
+
11
+ module Mnogootex
12
+ class CLI < Thor
13
+ IS_MNOGOO = (ENV['IS_MNOGOO'] == 'true')
14
+
15
+ def self.basename
16
+ IS_MNOGOO ? 'mnogoo' : super
17
+ end
18
+
19
+ desc 'cd [JOB] [MAIN]',
20
+ 'Check into dir of JOB (or source) for MAIN (or inferred) document'
21
+ def cd(*args); end
22
+
23
+ desc 'open [JOB ...] [MAIN]',
24
+ 'Open PDF of each (or every) JOB for MAIN (or inferred) document'
25
+ def open(*args); end
26
+
27
+ remove_command :cd, :open unless IS_MNOGOO
28
+
29
+ desc 'mnogoo',
30
+ 'Print path of the shell wrapper script'
31
+ def mnogoo
32
+ puts Pathname.new(__dir__).join('mnogoo.sh').realpath
33
+ end
34
+
35
+ desc 'clobber',
36
+ 'Clean up all temporary files'
37
+ def clobber
38
+ # NOTE: this is a tad slow - using shell would improve that
39
+ # TODO: this does not account for custom work_path
40
+ tmp_dir = Pathname.new(Dir.tmpdir).join('mnogootex')
41
+ tmp_dir_size = Mnogootex::Utils.humanize_bytes Mnogootex::Utils.dir_size(tmp_dir)
42
+ print "Freeing up #{tmp_dir_size}... "
43
+ FileUtils.rm_r tmp_dir, secure: true if tmp_dir.directory?
44
+ puts 'Done.'
45
+ end
46
+
47
+ desc 'go [JOB ...] [MAIN]',
48
+ 'Run each (or every) JOB for MAIN (or inferred) document'
49
+ def go(*args)
50
+ _, main, cfg = Mnogootex::Cfg.recombobulate(*args)
51
+ cfg = Mnogootex::Cfg::DEFAULTS.merge cfg
52
+ Mnogootex::Job::Warden.new(source: main, configuration: cfg).start
53
+ end
54
+
55
+ desc 'dir [JOB] [MAIN]',
56
+ 'Print dir of JOB (or source) for MAIN (or inferred) document'
57
+ def dir(*args)
58
+ jobs, main, cfg = Mnogootex::Cfg.recombobulate(*args)
59
+
60
+ if jobs.empty?
61
+ puts main.dirname
62
+ else
63
+ jobs.map! { |hid| Mnogootex::Job::Porter.new hid: hid, source_path: main, work_path: cfg['work_path'] }
64
+ jobs.map!(&:target_dir)
65
+ puts jobs
66
+ end
67
+ end
68
+
69
+ desc 'pdf [JOB ...] [MAIN]',
70
+ 'Print PDF path of each (or every) JOB for MAIN (or inferred) document'
71
+ def pdf(*args)
72
+ jobs, main, cfg = Mnogootex::Cfg.recombobulate(*args)
73
+
74
+ jobs = cfg['jobs'] if jobs.empty?
75
+ jobs.map! { |hid| Mnogootex::Job::Porter.new hid: hid, source_path: main, work_path: cfg['work_path'] }
76
+ jobs.map! { |porter| porter.target_path.sub_ext('.pdf') }
77
+ puts jobs
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Object
4
+ def if
5
+ tap { |object| break unless yield object }
6
+ end
7
+
8
+ def unless
9
+ tap { |object| break if yield object }
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ # This is the default configuration file
2
+ spinner: ⣾⣽⣻⢿⡿⣟⣯⣷
3
+ commandline:
4
+ - latexmk
5
+ - -pdf
6
+ - --interaction=nonstopmode
7
+ work_path: null