mnogootex 1.1.0 → 2.0.0

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
  SHA256:
3
- metadata.gz: 654469a2719e7a34e16be659b3b59cbf8611f1f5025ccba19ba1bea60e35d87b
4
- data.tar.gz: cc026af91f6270d36fd5affa76565e49ba781638965cb0b377c8775d84cbc8fb
3
+ metadata.gz: edf454b8fab7fe98488bade01dd2c59b3419d5afb9bc4a6c7cadca1cd36bf296
4
+ data.tar.gz: 1036a5f4e565b1deef11daa6c5418eeb4f357e942fc55009d92f7fc6cfd9dcbe
5
5
  SHA512:
6
- metadata.gz: 2cf80aa5a52753bfec92a5ce7a6ff1c0a1d3d84376fdc897ed364097b52126245e5852284b474e81adee288c30d316753cb0bd38b8d75fbf541345512c834754
7
- data.tar.gz: a71bda28d8eded4790cb3b40b6b673c58e3f96e630e42bb512c80afd004f869f559938ff83c7fb358780f59007c4117cad5bd0cf0b20e9d956c9c1d81425cfac
6
+ metadata.gz: 0c47604bd0302b39ab98ac7417fd0b1b720360c6e54650cc99383237ef2c42cbc65b2edebad71b44d7a662a21aa3740b6f71a66712b87af09d253d86de142989
7
+ data.tar.gz: 7e00d8a660f75ac7e04e0ba8befea9553f33d8f94b692f31bd634f333043a29abf0eb6eef619389dbf1cc31496ea299ed101b0f4311080ce0e47904983aa939a
@@ -0,0 +1,34 @@
1
+ name: Setup Ruby
2
+ description: Setup Ruby
3
+ inputs:
4
+ ruby-version:
5
+ required: false
6
+ default: '2.7'
7
+ cache-path:
8
+ required: false
9
+ default: vendor/bundle
10
+ cache-key:
11
+ required: false
12
+ default: gems-
13
+ cache-restore-keys:
14
+ required: false
15
+ default: gems-
16
+ outputs: {}
17
+ runs:
18
+ using: "composite"
19
+ steps:
20
+ - name: Setup Ruby
21
+ uses: ruby/setup-ruby@v1
22
+ with:
23
+ ruby-version: ${{ inputs.ruby-version }}
24
+ - name: Cache Ruby gems
25
+ uses: actions/cache@v2
26
+ with:
27
+ path: ${{ inputs.cache-path }}
28
+ key: ${{ inputs.cache-key }}
29
+ restore-keys: ${{ inputs.cache-restore-keys }}
30
+ - name: Install Ruby gems
31
+ shell: bash
32
+ run: |
33
+ bundle config path ${{ inputs.cache-path }}
34
+ bundle install --jobs 4 --retry 3
@@ -5,37 +5,40 @@ on:
5
5
  pull_request:
6
6
 
7
7
  jobs:
8
- main:
9
- name: >-
10
- ${{ matrix.os }} ${{ matrix.ruby }}
11
- runs-on: ${{ matrix.os }}-latest
8
+
9
+ test:
10
+ runs-on: ${{ matrix.os }}
12
11
  strategy:
13
12
  fail-fast: false
14
13
  matrix:
15
- os: [ ubuntu, macos ]
14
+ os: [ 'ubuntu-latest', 'macos-latest' ]
16
15
  ruby: [ '2.6', '2.7', '3.0' ]
16
+ include:
17
+ - os: ubuntu-latest
18
+ ruby: '2.7'
19
+ coverage: true
17
20
 
18
21
  steps:
19
22
 
20
23
  - name: Checkout repo
21
24
  uses: actions/checkout@v2
22
25
 
23
- - name: Set up Ruby
24
- uses: ruby/setup-ruby@v1
26
+ - name: Setup Ruby
27
+ uses: ./.github/actions/setup-ruby
25
28
  with:
26
29
  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
30
+ cache-key: gems-${{ matrix.os }}-${{ matrix.ruby }}-${{ hashFiles('Gemfile', 'mnogootex.gemspec') }}
31
+ cache-restore-keys: gems-${{ matrix.os }}-${{ matrix.ruby }}-
39
32
 
40
33
  - name: Run tests
41
34
  run: bundle exec rake spec:rspec
35
+
36
+ - name: Test and publish coverage to Code Climate
37
+ uses: paambaati/codeclimate-action@v3.0.0
38
+ if: ${{ matrix.coverage && github.ref == 'refs/heads/main' }}
39
+ env:
40
+ CC_TEST_REPORTER_ID: 890ed5ee01002c7149920883256f8e4790000127faa9ddf14d86dd3ceb3b8179
41
+ COVERAGE: true
42
+ with:
43
+ coverageCommand: bundle exec rspec
44
+ coverageLocations: ${{ github.workspace }}/coverage/coverage.json:simplecov
data/.rubocop.yml CHANGED
@@ -5,6 +5,8 @@ Metrics/LineLength:
5
5
  Max: 120
6
6
  Layout/DotPosition:
7
7
  EnforcedStyle: trailing
8
+ Style/TrailingCommaInArguments:
9
+ EnforcedStyleForMultiline: consistent_comma
8
10
  Metrics/BlockLength:
9
11
  Exclude:
10
12
  - spec/**/*_spec.rb
data/CHANGELOG.md ADDED
@@ -0,0 +1,55 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [2.0.0] - 2021-11-19
11
+
12
+ ### Added
13
+
14
+ - `exec` command to run `latexmk` directly.
15
+ - `clobber` command to delete both unessential files and artifacts.
16
+
17
+ ### Changed
18
+
19
+ - `go` command renamed to `build`.
20
+ - `clean` command simply deletes unessential files (instead of everything).
21
+ - Configuration must be named `.mnogootexrc` (instead of `.mnogootex.yml`).
22
+
23
+ ### Removed
24
+
25
+ - `mnogoo` shell integration no longer exists.
26
+ - `dir` and `pdf` commands no longer exist.
27
+
28
+ ### Fixed
29
+
30
+ - Avoid deleting files before buils so viewers can reload.
31
+ - Caught nasty IO timing bug when polling `latexmk -pv` for logs.
32
+
33
+ ## [1.1.0] - 2021-11-06
34
+
35
+ ### Added
36
+
37
+ - New option `work_path` in configuration file to simplify access to build folders.
38
+
39
+ ## [1.0.1] - 2018-09-03
40
+
41
+ ### Fixed
42
+
43
+ - `mnogootex mnogoo` now produces correct path.
44
+
45
+ ## [1.0.0] - 2018-04-24
46
+
47
+ ### Added
48
+
49
+ - First public release.
50
+
51
+ [unreleased]: https://github.com/paolobrasolin/mnogootex/compare/v2.0.0...HEAD
52
+ [2.0.0]: https://github.com/paolobrasolin/mnogootex/compare/v1.1.0...v2.0.0
53
+ [1.1.0]: https://github.com/paolobrasolin/mnogootex/compare/v1.0.1...v1.1.0
54
+ [1.0.1]: https://github.com/paolobrasolin/mnogootex/compare/v1.0.0...v1.0.1
55
+ [1.0.0]: https://github.com/paolobrasolin/mnogootex/releases/tag/v1.0.0
data/README.md CHANGED
@@ -1,12 +1,21 @@
1
1
  # Многоꙮтех
2
2
 
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) -->
3
+ [![CI tests status badge][build-shield]][build-url]
4
+ [![Latest release badge][rubygems-shield]][rubygems-url]
5
+ [![License badge][license-shield]][license-url]
6
+ [![Maintainability badge][cc-maintainability-shield]][cc-maintainability-url]
7
+ [![Test coverage badge][cc-coverage-shield]][cc-coverage-url]
8
+
9
+ [build-shield]: https://img.shields.io/github/workflow/status/paolobrasolin/mnogootex/CI/main?label=tests&logo=github
10
+ [build-url]: https://github.com/paolobrasolin/mnogootex/actions/workflows/main.yml "CI tests status"
11
+ [rubygems-shield]: https://img.shields.io/gem/v/mnogootex?logo=ruby
12
+ [rubygems-url]: https://rubygems.org/gems/mnogootex "Latest release"
13
+ [license-shield]: https://img.shields.io/github/license/paolobrasolin/mnogootex
14
+ [license-url]: https://github.com/paolobrasolin/mnogootex/blob/main/LICENSE "License"
15
+ [cc-maintainability-shield]: https://img.shields.io/codeclimate/maintainability/paolobrasolin/mnogootex?logo=codeclimate
16
+ [cc-maintainability-url]: https://codeclimate.com/github/paolobrasolin/mnogootex "Maintainability"
17
+ [cc-coverage-shield]: https://img.shields.io/codeclimate/coverage/paolobrasolin/mnogootex?logo=codeclimate&label=test%20coverage
18
+ [cc-coverage-url]: https://codeclimate.com/github/paolobrasolin/mnogootex/coverage "Test coverage"
10
19
 
11
20
  Многоꙮтех (mnogootex) is a utility that parallelizes compilation
12
21
  of a LaTeX document using different classes and offers a
@@ -16,174 +25,259 @@ The motivating use case is maintaining a single preamble while
16
25
  submitting a paper to many journals using their outdated or crummy
17
26
  document classes.
18
27
 
19
- ## Installation
28
+ ## Getting started
20
29
 
21
- The only requirement is [Ruby](https://www.ruby-lang.org) (>=2.5 as earlier versions are untested).
30
+ ### Prerequisites
31
+
32
+ Многоꙮтех is written in [**Ruby**](https://www.ruby-lang.org) and requires version `>=2.5` (earlier ones are untested).
33
+ You can check whether it's installed by running `ruby --version`.
34
+ For installation instructions you can refer to the [official documentation](https://www.ruby-lang.org/en/documentation/installation/).
35
+
36
+
37
+ Многоꙮтех heavily relies on [**`latexmk`**](https://ctan.org/pkg/latexmk).
38
+ You can check whether it's installed by running `latexmk --version`.
39
+ If you are missing it, follow the documentation of your specific LaTeX distribution and install the `latexmk` package.
40
+
41
+ ### Installation
22
42
 
23
43
  To install многоꙮтех execute
24
44
 
25
- gem install mnogootex
26
-
27
- To install `mnogoo` (strongly recommended shell integration) add this to your shell profile
45
+ ```bash
46
+ gem install mnogootex
47
+ ```
48
+
49
+ If you're upgrading from a previous version, execute
28
50
 
29
- [ -s "$(mnogootex mnogoo)" ] && . "$(mnogootex mnogoo)"
51
+ ```bash
52
+ gem update mnogootex
53
+ ```
30
54
 
31
- ## Quick start
55
+ and remove any mention of `mnogootex` from your shell profile (it's not needed anymore).
32
56
 
33
- Set up your `LaTeX` project as usual - let's say its main file is `~/project/main.tex` and contains `\documentclass{...}`.
57
+ ### Quick start
34
58
 
35
- Create a configuration file `~/project/.mnogootex.yml`
36
- containing the list of document classes you want to compile your
37
- project against:
59
+ First you write a LaTeX document:
38
60
 
39
- jobs:
40
- - scrartcl
41
- - article
42
- - book
43
-
44
- Run `mnogootex go ~/project/main.tex` and enjoy the technicolor:
61
+ ```latex
62
+ % ~/demo/main.tex
63
+ \documentclass{scrarticle}
64
+ \begin{document}
65
+ \abstract{Simply put, my article is awesome.}
66
+ Let's port my \KOMAScript\ article to other classes!
67
+ \end{document}
68
+ ```
45
69
 
46
- ![Demo TTY GIF](tty.gif?raw=true "Demo TTY GIF")
70
+ Then you list the desided classes in a Многоꙮтех configuration file:
71
+
72
+ ```yaml
73
+ # ~/demo/.mnogootexrc
74
+ jobs:
75
+ - scrartcl
76
+ - article
77
+ - book
78
+ ```
79
+
80
+ Finally you run `mnogootex build` and enjoy the technicolor:
81
+
82
+ ![A user types `mnogootex build main.tex` in the console. Some spinners indicating progress appear. Then the outcome for each class is presented. Failing ones include abridged and color coded logs, to pinpoint the errors.](demo/demo.gif?raw=true "TTY demo GIF")
47
83
 
48
84
  ## Usage
49
85
 
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.
86
+ A Многоꙮтех run does the following:
87
+ 1. copy the _source_ folder of a project to many _target_ folders, one for each _job_;
88
+ 2. replace the document class in the source of each _target_ folder with the name of the relative _job_;
89
+ 3. call `latexmk` in parallel on each _target_ folder to compile the documents (or do other tasks);
90
+ 4. wait for the outcomes and print the logs, filtered and colour-coded in a meaningful way.
55
91
 
56
92
  Its convenience lies in the fact that it
57
93
  * automates the setup process,
58
94
  * parallelizes compilation,
59
- * filters and colour codes the infamous waterfall logs and
60
- * allows you to easily navigate through targets/source folders.
95
+ * improves the readability of the infamous waterfall logs.
61
96
 
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.
97
+ Многоꙮтех can be invoked from CLI using `mnogootex`.
98
+ It accepts various [commands](#mnogootex-commands) detailed below.
64
99
 
65
- Commands listed below can be passed to both unless otherwise stated.
100
+ To leverage the full power of this tool you will need to learn writing [`mnogootex` configurations](#mnogootex-configuration) and ['latexmk' configurations](#latexmk-configuration).
101
+ It might sound daunting but they're really just a few lines.
66
102
 
67
- ### Commands
103
+ ### `mnogootex` commands
68
104
 
69
- > **NOTATION:** `[FOO]` means that _`FOO` is optional_ while `FOO ...` means _one or more `FOO`s_.
70
-
71
- #### `help [COMMAND]`
105
+ > **Notation:** `[FOO]` means that _`FOO` is optional_ while `FOO ...` means _one or more `FOO`s_.
72
106
 
73
- Prints the help for `COMMAND` (or all commands if none is given).
107
+ All commands except `help` accept the same parameters, so let's examine them in advance to avoid repeating ourselves later.
108
+ Here is their syntax:
74
109
 
75
- #### `mnogoo`
110
+ ```bash
111
+ mnogootex COMMAND [JOB ...] [FLAG ...] ROOT
112
+ ```
76
113
 
77
- Prints the location of the `mnogoo` shell integration script.
78
- Useful only for its [installation](#installation).
114
+ `JOB`s are the names of the document classes to compile your document with.
115
+ Zero or more can be provided, and when none is given the job list is loaded from the [configuration](#jobs).
79
116
 
80
- #### `go [JOB ...] [MAIN]`
117
+ `FLAG`s are `latexmk` options.
118
+ Zero or more can be provided to override the behaviour of the `latexmk` call underlying the `mnogootex` command.
119
+ You can obtain a list of available options with the inline help `latexmk --help`, and the full documentation with `man latexmk`.
120
+ Generally speaking, if you find yourself always using a `FLAG` you should properly [configure `latexmk`](#latexmk-configuration) instead.
81
121
 
82
- Run given compilation `JOB`s for the `MAIN` document.
122
+ The last mandatory parameter is the `ROOT` file for compiling of your document.
83
123
 
84
- If no `JOB` list is given then all of them are run.
85
- They are deduced from the [configuration](#configuration).
124
+ Let's examine the details of each command now.
86
125
 
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.
126
+ #### `help [COMMAND]`
93
127
 
94
- If no `JOB` is given then it prints the source directory.
128
+ This command prints the help for `COMMAND` (or all commands if none is given).
95
129
 
96
- If no `MAIN` document is given then it's deduced from either
97
- your current working directory or the [configuration](#configuration).
130
+ #### `exec [JOB ...] [FLAG ...] ROOT`
98
131
 
99
- #### `cd [JOB] [MAIN]`
132
+ This command simply runs `latexmk` on the `ROOT` document for each of your `JOB`s passing the given `FLAG`s.
100
133
 
101
- > **NOTE:** recognized by `mnogoo` only.
134
+ All other commands below are specializations of this one.
135
+ However you'll seldom use it unless you're debugging.
102
136
 
103
- Checks into `JOB`'s temporary directory for the `MAIN` document.
137
+ #### `build [JOB ...] [FLAG ...] ROOT`
104
138
 
105
- If no `JOB` is given then it checks into the source directory.
139
+ This command builds your document.
106
140
 
107
- If no `MAIN` document is given then it's deduced from either
108
- your current working directory or the [configuration](#configuration).
141
+ It is equivalent to `exec [JOB ...] -interaction=nonstopmode ROOT`.
109
142
 
110
- #### `clobber`
143
+ You will probably need to pass some `FLAG`s (e.g. to use the correct engine) but it is not recommended: [configure `latexmk`](#latexmk-configuration) instead.
111
144
 
112
- Deletes all temporary files.
113
- Useful to free up some space from time to time.
145
+ #### `open [JOB ...] [FLAG ...] ROOT`
114
146
 
115
- #### `pdf [JOB ...] [MAIN]`
147
+ This command opens the final compilation artifact (after running the build if necessary).
116
148
 
117
- Print `JOB`'s output PDF path for the `MAIN` document.
149
+ It is equivalent to `exec [JOB ...] -pv -interaction=nonstopmode ROOT`.
118
150
 
119
- If no `JOB` list is given then all their output PDFs paths are printed.
120
- They are deduced from the [configuration](#configuration).
151
+ You might need to pass some `FLAG`s (e.g. to use the correct viewer) but it is not recommended: [configure `latexmk`](#latexmk-configuration) instead.
121
152
 
122
- If no `MAIN` document is given then it's deduced from either
123
- your current working directory or the [configuration](#configuration).
153
+ #### `clean [JOB ...] [FLAG ...] ROOT`
124
154
 
125
- #### `open [JOB ...] [MAIN]`
155
+ This command deletes all nonessential build files while keeping the compiled artifacts.
126
156
 
127
- > **NOTE:** recognized by `mnogoo` only.
157
+ It is equivalent to `exec [JOB ...] -c ROOT`.
128
158
 
129
- Open `JOB`'s output PDF for the `MAIN` document with your default viewer.
159
+ #### `clobber [JOB ...] [FLAG ...] ROOT`
130
160
 
131
- If no `JOB` list is given then all their output PDFs are opened.
132
- They are deduced from the [configuration](#configuration).
161
+ This command deletes all nonessential build files including the compiled artifacts.
133
162
 
134
- If no `MAIN` document is given then it's deduced from either
135
- your current working directory or the [configuration](#configuration).
163
+ It is equivalent to `exec [JOB ...] -C ROOT`.
136
164
 
137
- ### Configuration
165
+ ### `mnogootex` configuration
138
166
 
139
- Многоꙮтех is configured through [`YAML`](https://learnxinyminutes.com/docs/yaml/)
140
- files named `.mnogootex.yml` put into your projects' root directory.
167
+ `mnogootex` is configured through [`YAML`](https://learnxinyminutes.com/docs/yaml/)
168
+ files named `.mnogootexrc` put into your projects' root directory.
141
169
 
142
- When loads a configuration it also looks up for `.mnogootex.yml`
170
+ When `mnogootex` loads a configuration it also looks up for `.mnogootexrc`
143
171
  files in all parent directories to merge then together (from the
144
172
  shallowest to the deepest path). This means that e.g. you can keep
145
173
  a configuration file in your home folder and use it as a global
146
174
  configuration for all you projects, while overwriting only specific
147
175
  options in the configuration files of each one.
148
176
 
149
- Многоꙮтех currently accepts three options.
177
+ `mnogootex` currently accepts three options.
150
178
 
151
- #### `spinner`
179
+ #### `jobs`
180
+
181
+ This option represents the `JOB`s to build your document (when none are given via CLI).
152
182
 
153
- This option is a string whose characters are the frames used to
154
- animate the spinners for the command line interface.
183
+ It must contain valid document class names, given as a list of strings.
155
184
 
156
- # Default value:
157
- spinner: ⣾⣽⣻⢿⡿⣟⣯⣷
185
+ By default there are no `JOB`s:
158
186
 
159
- #### `commandline`
187
+ ```yaml
188
+ # Default value:
189
+ jobs: []
190
+ ```
160
191
 
161
- This option is an array of the components for the commandline used
162
- to compile documents.
192
+ Here is a slightly more interesting example:
163
193
 
164
- # Default value:
165
- commandline:
166
- - latexmk
167
- - -pdf
168
- - --interaction=nonstopmode
194
+ ```yaml
195
+ jobs:
196
+ - scrartcl
197
+ - article
198
+ - book
199
+ ```
169
200
 
170
201
  #### `work_path`
171
202
 
172
- This option is an override for the path where compilation happens.
203
+ This option is the folder where all elaboration happens.
204
+
205
+ It must be a well formed path, given as a string.
206
+
207
+ By default none is given, meaning that each run of any given job happens in a dedicated temporary folder:
208
+
209
+ ```yaml
210
+ # Default value:
211
+ work_path: null
212
+ ```
213
+
214
+ Overriding this allows you to have easier access to the compilation artifacts.
215
+ A good choice is setting it to `./build` and keep everything below your source folder:
216
+
217
+ ```yaml
218
+ work_path: ./build
219
+ ```
220
+
221
+ #### `spinner`
222
+
223
+ This option is the spinner animation shown by the CLI.
224
+
225
+ It is a series of frames given as characters of a string.
226
+
227
+ By default it's a hole looping around in a blister:
228
+
229
+ ```yaml
230
+ # Default value:
231
+ spinner: ⣾⣽⣻⢿⡿⣟⣯⣷
232
+ ```
233
+
234
+ Here is a couple more in case your terminal doesn't like Unicode:
235
+
236
+ ```yaml
237
+ # A wriggly ASCII worm:
238
+ spinner: )}]|[{({[|]}
239
+ # An extended ASCII boomerang:
240
+ spinner: ╒┍┌┎╓╖┒┐┑╕╛┙┘┚╜╙┖└┕╘
241
+ ```
242
+
243
+ Feel free to get creative!
244
+
245
+ ### `latexmk` configuration
246
+
247
+ `latexmk` is configured through [`Perl`](https://www.perl.org/)
248
+ files named `.latexmkrc` put into your projects' root directory.
249
+
250
+ When `latexmk` loads a configuration it also looks up for `.latexmkrc`
251
+ files in all parent directories to merge then together (from the
252
+ shallowest to the deepest path). This means that e.g. you can keep
253
+ a configuration file in your home folder and use it as a global
254
+ configuration for all you projects, while overwriting only specific
255
+ options in the configuration files of each one.
173
256
 
174
- # Default value:
175
- work_path: null
257
+ `latexmk` has a gazillion of options.
258
+ We'll just skim over the most common ones here.
176
259
 
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.
260
+ First of all, one must pick the correct engine.
261
+ Assuming you want to produce a PDF artifact, you have a few choices:
178
262
 
179
- ## Contributing
263
+ ```perl
264
+ $pdf_mode = 1; # create PDF with pdflatex
265
+ # $pdf_mode = 2; # create PDF with ps2pdf (via PS)
266
+ # $pdf_mode = 3; # create PDF with dvipdf (via DVI)
267
+ # $pdf_mode = 4; # create PDF with lualatex
268
+ # $pdf_mode = 5; # create PDF with xelatex
269
+ ```
180
270
 
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.
271
+ Then, if your PDF previewer is not being detected, you might need to configure it.
272
+ Assuming you want to use evince:
182
273
 
183
- ## License
274
+ ```perl
275
+ $pdf_previewer = 'start evince';
276
+ ```
184
277
 
185
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
278
+ Most people won't probably need anything more than that.
279
+ However, for further details read the documentation in the commandline with `man latexmk` or on [CTAN](https://ctan.mirror.garr.it/mirrors/ctan/support/latexmk/latexmk.txt)
186
280
 
187
- ## Code of Conduct
281
+ ## Acknowledgements
188
282
 
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).
283
+ * Thanks to [@tetrapharmakon](https://github.com/tetrapharmakon) for being the first tester and user.
data/demo/.mnogootexrc ADDED
@@ -0,0 +1,4 @@
1
+ jobs:
2
+ - scrarticle
3
+ - article
4
+ - book
@@ -0,0 +1,114 @@
1
+ {"version": 2, "width": 92, "height": 26, "timestamp": 1637333757, "env": {"SHELL": "/bin/zsh", "TERM": "alacritty"}}
2
+ [0.017014, "o", "\u001b[?2004h$ "]
3
+ [0.816219, "o", "m"]
4
+ [0.880306, "o", "n"]
5
+ [1.120106, "o", "o"]
6
+ [1.328005, "o", "g"]
7
+ [1.431937, "o", "o"]
8
+ [1.560266, "o", "o"]
9
+ [1.664007, "o", "t"]
10
+ [1.824229, "o", "e"]
11
+ [2.096341, "o", "x"]
12
+ [2.208064, "o", " "]
13
+ [2.416225, "o", "b"]
14
+ [2.488119, "o", "u"]
15
+ [2.528114, "o", "i"]
16
+ [2.775867, "o", "l"]
17
+ [2.927851, "o", "d"]
18
+ [3.048131, "o", " "]
19
+ [3.18416, "o", "m"]
20
+ [3.30414, "o", "a"]
21
+ [3.360091, "o", "i"]
22
+ [3.463861, "o", "n"]
23
+ [3.664082, "o", "."]
24
+ [3.768087, "o", "t"]
25
+ [3.872092, "o", "e"]
26
+ [4.072065, "o", "x"]
27
+ [4.19206, "o", "\r\n\u001b[?2004l\r"]
28
+ [4.610511, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\r"]
29
+ [4.630807, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\r"]
30
+ [4.652109, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\r"]
31
+ [4.672831, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\r"]
32
+ [4.693597, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\r"]
33
+ [4.71437, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\r"]
34
+ [4.735132, "o", "Runners: \u001b[0;33;49m⣽\u001b[0m\u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\r"]
35
+ [4.755441, "o", "Runners: \u001b[0;33;49m⣻\u001b[0m\u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\r"]
36
+ [4.776142, "o", "Runners: \u001b[0;33;49m⢿\u001b[0m\u001b[0;33;49m⣽\u001b[0m\u001b[0;33;49m⣽\u001b[0m\r"]
37
+ [4.796857, "o", "Runners: \u001b[0;33;49m⡿\u001b[0m\u001b[0;33;49m⣻\u001b[0m\u001b[0;33;49m⣻\u001b[0m\r"]
38
+ [4.817161, "o", "Runners: \u001b[0;33;49m⣟\u001b[0m\u001b[0;33;49m⢿\u001b[0m\u001b[0;33;49m⢿\u001b[0m\r"]
39
+ [4.837458, "o", "Runners: \u001b[0;33;49m⣯\u001b[0m\u001b[0;33;49m⡿\u001b[0m\u001b[0;33;49m⡿\u001b[0m\r"]
40
+ [4.857789, "o", "Runners: \u001b[0;33;49m⣷\u001b[0m\u001b[0;33;49m⣟\u001b[0m\u001b[0;33;49m⣟\u001b[0m\r"]
41
+ [4.878122, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣯\u001b[0m\u001b[0;33;49m⣯\u001b[0m\r"]
42
+ [4.898448, "o", "Runners: \u001b[0;33;49m⣽\u001b[0m\u001b[0;33;49m⣷\u001b[0m\u001b[0;33;49m⣷\u001b[0m\r"]
43
+ [4.918754, "o", "Runners: \u001b[0;33;49m⣻\u001b[0m\u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣾\u001b[0m\r"]
44
+ [4.939493, "o", "Runners: \u001b[0;33;49m⢿\u001b[0m\u001b[0;33;49m⣽\u001b[0m\u001b[0;33;49m⣽\u001b[0m\r"]
45
+ [4.960303, "o", "Runners: \u001b[0;33;49m⡿\u001b[0m\u001b[0;33;49m⣻\u001b[0m\u001b[0;33;49m⣻\u001b[0m\r"]
46
+ [4.980995, "o", "Runners: \u001b[0;33;49m⣟\u001b[0m\u001b[0;33;49m⢿\u001b[0m\u001b[0;33;49m⢿\u001b[0m\r"]
47
+ [5.001721, "o", "Runners: \u001b[0;33;49m⣯\u001b[0m\u001b[0;33;49m⡿\u001b[0m\u001b[0;33;49m⡿\u001b[0m\r"]
48
+ [5.022407, "o", "Runners: \u001b[0;33;49m⣷\u001b[0m\u001b[0;33;49m⣟\u001b[0m\u001b[0;33;49m⣟\u001b[0m\r"]
49
+ [5.042661, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;33;49m⣯\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
50
+ [5.062924, "o", "Runners: \u001b[0;33;49m⣽\u001b[0m\u001b[0;33;49m⣷\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
51
+ [5.083219, "o", "Runners: \u001b[0;33;49m⣻\u001b[0m\u001b[0;33;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
52
+ [5.10347, "o", "Runners: \u001b[0;33;49m⢿\u001b[0m\u001b[0;33;49m⣽\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
53
+ [5.123727, "o", "Runners: \u001b[0;33;49m⡿\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
54
+ [5.143997, "o", "Runners: \u001b[0;33;49m⣟\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
55
+ [5.164261, "o", "Runners: \u001b[0;33;49m⣯\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
56
+ [5.18454, "o", "Runners: \u001b[0;33;49m⣷\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
57
+ [5.204898, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
58
+ [5.225157, "o", "Runners: \u001b[0;33;49m⣽\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
59
+ [5.245427, "o", "Runners: \u001b[0;33;49m⣻\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
60
+ [5.265709, "o", "Runners: \u001b[0;33;49m⢿\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
61
+ [5.285988, "o", "Runners: \u001b[0;33;49m⡿\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
62
+ [5.306276, "o", "Runners: \u001b[0;33;49m⣟\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
63
+ [5.326587, "o", "Runners: \u001b[0;33;49m⣯\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
64
+ [5.346862, "o", "Runners: \u001b[0;33;49m⣷\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
65
+ [5.367137, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
66
+ [5.387471, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
67
+ [5.407789, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
68
+ [5.428094, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
69
+ [5.448427, "o", "Runners: \u001b[0;33;49m⣽\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
70
+ [5.468685, "o", "Runners: \u001b[0;33;49m⣻\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
71
+ [5.48902, "o", "Runners: \u001b[0;33;49m⢿\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
72
+ [5.509286, "o", "Runners: \u001b[0;33;49m⡿\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
73
+ [5.529559, "o", "Runners: \u001b[0;33;49m⣟\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
74
+ [5.549834, "o", "Runners: \u001b[0;33;49m⣯\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
75
+ [5.570114, "o", "Runners: \u001b[0;33;49m⣷\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
76
+ [5.590495, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
77
+ [5.610773, "o", "Runners: \u001b[0;33;49m⣽\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
78
+ [5.631053, "o", "Runners: \u001b[0;33;49m⣻\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
79
+ [5.651328, "o", "Runners: \u001b[0;33;49m⢿\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
80
+ [5.671634, "o", "Runners: \u001b[0;33;49m⡿\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
81
+ [5.691885, "o", "Runners: \u001b[0;33;49m⣟\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
82
+ [5.712144, "o", "Runners: \u001b[0;33;49m⣯\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
83
+ [5.732409, "o", "Runners: \u001b[0;33;49m⣷\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
84
+ [5.752725, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
85
+ [5.77299, "o", "Runners: \u001b[0;33;49m⣽\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
86
+ [5.793269, "o", "Runners: \u001b[0;33;49m⣻\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
87
+ [5.81354, "o", "Runners: \u001b[0;33;49m⢿\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
88
+ [5.833802, "o", "Runners: \u001b[0;33;49m⡿\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
89
+ [5.854091, "o", "Runners: \u001b[0;33;49m⣟\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
90
+ [5.874667, "o", "Runners: \u001b[0;33;49m⣯\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
91
+ [5.894903, "o", "Runners: \u001b[0;33;49m⣷\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
92
+ [5.915157, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
93
+ [5.935432, "o", "Runners: \u001b[0;33;49m⣽\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
94
+ [5.955706, "o", "Runners: \u001b[0;33;49m⣻\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
95
+ [5.975985, "o", "Runners: \u001b[0;33;49m⢿\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
96
+ [5.996281, "o", "Runners: \u001b[0;33;49m⡿\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
97
+ [6.016565, "o", "Runners: \u001b[0;33;49m⣟\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
98
+ [6.03685, "o", "Runners: \u001b[0;33;49m⣯\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
99
+ [6.057124, "o", "Runners: \u001b[0;33;49m⣷\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
100
+ [6.077406, "o", "Runners: \u001b[0;33;49m⣾\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
101
+ [6.097789, "o", "Runners: \u001b[0;33;49m⣽\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
102
+ [6.118073, "o", "Runners: \u001b[0;33;49m⣻\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r"]
103
+ [6.138511, "o", "Runners: \u001b[0;32;49m⣯\u001b[0m\u001b[0;31;49m⣾\u001b[0m\u001b[0;31;49m⢿\u001b[0m\r\r\nOutcome:\r\n"]
104
+ [6.138712, "o", " \u001b[0;32;49m✔\u001b[0m scrarticle\r\n \u001b[0;31;49m✘\u001b[0m article\r\n"]
105
+ [6.139693, "o", " \u001b[0;97;49mLatexmk: This is Latexmk, John Collins, 21 September 2021, version: 4.75.\u001b[0m\r\n \u001b[0;97;49mThis is pdfTeX, Version 3.141592653-2.6-1.40.23 (TeX Live 2021) (preloaded format=latex)\u001b[0m\r\n \u001b[0;91;49m! Undefined control sequence.\u001b[0m\r\n \u001b[0;91;49ml.4 Let's port my \\KOMAScript\u001b[0m\r\n \u001b[0;91;49m \\ article!\u001b[0m\r\n \u001b[0;97;49mOutput written on main.dvi (1 page, 424 bytes).\u001b[0m\r\n \u001b[0;91;49mLatexmk: Errors, so I did not complete making targets\u001b[0m\r\n \u001b[0;31;49m✘\u001b[0m book\r\n"]
106
+ [6.140624, "o", " \u001b[0;97;49mLatexmk: This is Latexmk, John Collins, 21 September 2021, version: 4.75.\u001b[0m\r\n \u001b[0;97;49mThis is pdfTeX, Version 3.141592653-2.6-1.40.23 (TeX Live 2021) (preloaded format=latex)\u001b[0m\r\n \u001b[0;91;49m! Undefined control sequence.\u001b[0m\r\n \u001b[0;91;49ml.3 \\abstract\u001b[0m\r\n \u001b[0;91;49m {Simply put, my article is awesome.}\u001b[0m\r\n \u001b[0;91;49m! Undefined control sequence.\u001b[0m\r\n \u001b[0;91;49ml.4 Let's port my \\KOMAScript\u001b[0m\r\n"]
107
+ [6.140752, "o", " \u001b[0;91;49m \\ article!\u001b[0m\r\n \u001b[0;97;49mOutput written on main.dvi (1 page, 324 bytes).\u001b[0m\r\n \u001b[0;91;49mLatexmk: Errors, so I did not complete making targets\u001b[0m\r\n"]
108
+ [6.145564, "o", "\u001b[?2004h$ "]
109
+ [9.623727, "o", "e"]
110
+ [9.720091, "o", "x"]
111
+ [9.904131, "o", "i"]
112
+ [10.016153, "o", "t"]
113
+ [10.496203, "o", "\r\n\u001b[?2004l\r"]
114
+ [10.49658, "o", "exit\r\n"]
data/demo/demo.gif ADDED
Binary file
data/demo/main.tex ADDED
@@ -0,0 +1,5 @@
1
+ \documentclass{scrarticle}
2
+ \begin{document}
3
+ \abstract{Simply put, my article is awesome.}
4
+ Let's port my \KOMAScript\ article!
5
+ \end{document}
data/lib/mnogootex/cfg.rb CHANGED
@@ -3,12 +3,14 @@
3
3
  require 'yaml'
4
4
  require 'pathname'
5
5
 
6
- require 'mnogootex/core_ext'
7
-
8
6
  module Mnogootex
9
7
  module Cfg
10
- BASENAME = '.mnogootex.yml'
11
- DEFAULTS = YAML.load_file(Pathname.new(__dir__).join('defaults.yml'))
8
+ BASENAME = '.mnogootexrc'
9
+ DEFAULTS = {
10
+ 'jobs' => [],
11
+ 'spinner' => '⣾⣽⣻⢿⡿⣟⣯⣷',
12
+ 'work_path' => nil,
13
+ }.freeze
12
14
 
13
15
  def self.load_descending(pathname:, basename:)
14
16
  pathname.realpath.descend.
@@ -25,15 +27,22 @@ module Mnogootex
25
27
  class << self
26
28
  private
27
29
 
30
+ def split_jobs_and_flags(args)
31
+ # TODO: some kind of validation?
32
+ flags = args.drop_while { |arg| !arg.start_with?('-') }
33
+ jobs = args.take_while { |arg| !arg.start_with?('-') }
34
+ [(jobs unless jobs.empty?), (flags unless flags.empty?)]
35
+ end
36
+
28
37
  def try_args(*args)
29
38
  main = Pathname.new(args.fetch(-1, ''))
30
39
  return unless main.file?
31
40
 
32
41
  main = main.realpath
33
42
  cfg = load_descending(pathname: main.dirname, basename: BASENAME)
34
- jobs = args[0..-2].unless(&:empty?)
43
+ jobs, flags = split_jobs_and_flags(args[0..-2])
35
44
 
36
- [jobs, main, cfg]
45
+ [jobs, flags, main, cfg]
37
46
  end
38
47
 
39
48
  def try_link(*args)
@@ -42,20 +51,21 @@ module Mnogootex
42
51
 
43
52
  main = link.readlink.realpath
44
53
  cfg = load_descending(pathname: main.dirname, basename: BASENAME)
45
- jobs = args
54
+ jobs, flags = split_jobs_and_flags(args)
46
55
 
47
- [jobs, main, cfg]
56
+ [jobs, flags, main, cfg]
48
57
  end
49
58
 
50
59
  def try_cfgs(*args)
51
- yaml = Pathname.pwd.ascend.map { |p| p.join('.mnogootex.yml') }.detect(&:file?)
60
+ yaml = Pathname.pwd.ascend.map { |p| p.join('.mnogootexrc') }.detect(&:file?)
52
61
  return if yaml.nil?
53
62
 
54
63
  cfg = load_descending(pathname: yaml.dirname, basename: BASENAME)
55
- main = yaml.dirname.join(cfg.fetch('main', '')).if(&:file?)&.realpath
56
- jobs = args
64
+ main = yaml.dirname.join(cfg.fetch('main', ''))
65
+ main = main.file? ? main.realpath : nil
66
+ jobs, flags = split_jobs_and_flags(args)
57
67
 
58
- [jobs, main, cfg]
68
+ [jobs, flags, main, cfg]
59
69
  end
60
70
  end
61
71
  end
data/lib/mnogootex/cli.rb CHANGED
@@ -10,71 +10,54 @@ require 'mnogootex/cfg'
10
10
 
11
11
  module Mnogootex
12
12
  class CLI < Thor
13
- IS_MNOGOO = (ENV['IS_MNOGOO'] == 'true')
14
-
15
- def self.basename
16
- IS_MNOGOO ? 'mnogoo' : super
13
+ desc 'exec [JOB ...] [FLAG ...] ROOT',
14
+ 'Execute latexmk with FLAGs on each JOB for ROOT document'
15
+ def exec(*args)
16
+ execute_latexmk(*args, default_flags: [])
17
17
  end
18
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
19
+ desc 'build [JOB ...] [FLAG ...] ROOT',
20
+ 'Build each JOB for ROOT document'
21
+ def build(*args)
22
+ execute_latexmk(*args, default_flags: ['-interaction=nonstopmode'])
33
23
  end
34
24
 
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.'
25
+ desc 'open [JOB ...] [FLAG ...] ROOT',
26
+ '(Build and) open the artifact of each JOB for ROOT document'
27
+ def open(*args)
28
+ execute_latexmk(*args, default_flags: ['-interaction=nonstopmode', '-pv'])
45
29
  end
46
30
 
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
31
+ desc 'clean [JOB ...] [FLAG ...] ROOT',
32
+ 'Delete nonessential files of each JOB for ROOT document'
33
+ def clean(*args)
34
+ execute_latexmk(*args, default_flags: ['-c'])
53
35
  end
54
36
 
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
37
+ desc 'clobber [JOB ...] [FLAG ...] ROOT',
38
+ 'Delete nonessential files and artifacts of each JOB for ROOT document'
39
+ def clobber(*args)
40
+ execute_latexmk(*args, default_flags: ['-C'])
41
+ end
42
+
43
+ desc 'help [COMMAND]',
44
+ 'Describe available commands or one specific COMMAND'
45
+ def help(*args)
46
+ super
47
+
48
+ puts <<~EXTRA_HELP
49
+ JOBs are document class names. The default is the whole list in your configuration file.
50
+ FLAGs are options passed to latexmk. Please refer to `latexmk -help` for details.
51
+ EXTRA_HELP
67
52
  end
68
53
 
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)
54
+ private
73
55
 
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
56
+ def execute_latexmk(*args, default_flags: [])
57
+ jobs, flags, main, cfg = Mnogootex::Cfg.recombobulate(*args)
58
+ cfg = Mnogootex::Cfg::DEFAULTS.merge(cfg).merge({ 'jobs' => jobs }.compact)
59
+ flags = [*default_flags, *flags]
60
+ Mnogootex::Job::Warden.new(source: main, configuration: cfg, flags: flags).start
78
61
  end
79
62
  end
80
63
  end
@@ -33,12 +33,22 @@ module Mnogootex
33
33
  providable_files = @source_path.dirname.children
34
34
  providable_files.reject!(&@work_path.method(:==))
35
35
  FileUtils.cp_r providable_files, target_dir
36
- target_dir.join('.mnogootex.yml').tap { |p| p.delete if p.file? }
37
- target_dir.join('.mnogootex.src').make_symlink(@source_path)
36
+ remove_configuration(target_dir)
37
+ create_link_to_source(target_dir)
38
38
  end
39
39
 
40
40
  private
41
41
 
42
+ def remove_configuration(folder_path)
43
+ path = folder_path.join('.mnogootexrc')
44
+ path.delete if path.file?
45
+ end
46
+
47
+ def create_link_to_source(folder_path)
48
+ path = folder_path.join('.mnogootex.src')
49
+ path.make_symlink(@source_path) unless path.symlink?
50
+ end
51
+
42
52
  def calc_work_path(path)
43
53
  return Pathname.new(path) unless path.nil?
44
54
 
@@ -1,10 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'open3'
4
+ require 'io/wait'
4
5
 
5
6
  module Mnogootex
6
7
  module Job
7
8
  class Runner
9
+ POLLING_TIMEOUT = 0.02
10
+
8
11
  attr_reader :hid, :log_lines
9
12
 
10
13
  def initialize(cmd:, chdir:)
@@ -31,13 +34,27 @@ module Mnogootex
31
34
 
32
35
  def start_poller
33
36
  Thread.new do
34
- until (line = @stream.gets).nil?
35
- log_lines << line
36
- end
37
+ polling_loop
38
+
37
39
  # NOTE: waits on @thread and returns its value
38
40
  @thread.value
39
41
  end
40
42
  end
43
+
44
+ def polling_loop
45
+ loop do
46
+ if @stream.wait_readable(POLLING_TIMEOUT).nil?
47
+ # If the stream timeouts and the thread is dead we expect no nore data.
48
+ # This happens on commands like `latexmk -pv` which fork other processes.
49
+ break unless @thread.alive?
50
+ else
51
+ # If we reach EOF, we expect no more data.
52
+ break if (line = @stream.gets).nil?
53
+
54
+ log_lines << line
55
+ end
56
+ end
57
+ end
41
58
  end
42
59
  end
43
60
  end
@@ -11,9 +11,12 @@ require 'mnogootex/job/logger'
11
11
  module Mnogootex
12
12
  module Job
13
13
  class Warden
14
- def initialize(source:, configuration:)
14
+ LATEXMK_PATH = 'latexmk'
15
+
16
+ def initialize(source:, configuration:, flags:)
15
17
  @source = source
16
18
  @configuration = configuration
19
+ @flags = flags
17
20
 
18
21
  @processor = nil
19
22
  @porters = []
@@ -44,7 +47,7 @@ module Mnogootex
44
47
 
45
48
  def exec_porters
46
49
  @porters.each do |porter|
47
- porter.clobber
50
+ # porter.clobber
48
51
  porter.provide
49
52
  transformer(porter.hid, porter.target_path)
50
53
  end
@@ -54,7 +57,7 @@ module Mnogootex
54
57
  @runners = @porters.map do |porter|
55
58
  Mnogootex::Job::Runner.new(
56
59
  cmd: commandline(porter.target_path),
57
- chdir: porter.target_dir
60
+ chdir: porter.target_dir,
58
61
  )
59
62
  end
60
63
  end
@@ -65,7 +68,7 @@ module Mnogootex
65
68
  levels: Mnogootex::Log::DEFAULT_LEVELS,
66
69
  min_level: :info,
67
70
  colorize: true,
68
- indent_width: 4
71
+ indent_width: 4,
69
72
  )
70
73
  end
71
74
 
@@ -74,14 +77,15 @@ module Mnogootex
74
77
  spinner: @configuration['spinner'],
75
78
  processor: @processor.method(:run),
76
79
  runners: @runners,
77
- porters: @porters
80
+ porters: @porters,
78
81
  )
79
82
  end
80
83
 
81
84
  # TODO: generalize, integrate with Runner
82
85
  def commandline(target_pathname)
83
86
  [
84
- *@configuration['commandline'],
87
+ LATEXMK_PATH,
88
+ *@flags,
85
89
  target_pathname.basename.to_s
86
90
  ]
87
91
  end
@@ -91,7 +95,7 @@ module Mnogootex
91
95
  old_code = target_pathname.read
92
96
  new_code = old_code.sub(
93
97
  /\\documentclass(\[.*?\])?{.*?}/,
94
- "\\documentclass{#{new_class_name}}"
98
+ "\\documentclass{#{new_class_name}}",
95
99
  )
96
100
  target_pathname.write(new_code)
97
101
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mnogootex
4
- VERSION = '1.1.0'
4
+ VERSION = '2.0.0'
5
5
  end
@@ -76,7 +76,7 @@ describe Mnogootex::Job::Porter do
76
76
  before do
77
77
  test_dir.join('A', 'B').mkpath
78
78
  test_dir.join('A', 'main.file').write('')
79
- test_dir.join('A', '.mnogootex.yml').write('')
79
+ test_dir.join('A', '.mnogootexrc').write('')
80
80
  test_dir.join('A', '.dotfile').write('')
81
81
  test_dir.join('A', 'B', 'ancillary.file').write('')
82
82
  end
@@ -89,9 +89,9 @@ describe Mnogootex::Job::Porter do
89
89
  end
90
90
 
91
91
  it 'ignores configuration file' do
92
- test_dir.join('A', '.mnogootex.yml').unlink
92
+ test_dir.join('A', '.mnogootexrc').unlink
93
93
  subject.provide
94
- expect(subject.target_dir.join('.mnogootex.yml')).to_not exist
94
+ expect(subject.target_dir.join('.mnogootexrc')).to_not exist
95
95
  end
96
96
 
97
97
  it 'creates link to source' do
@@ -108,7 +108,7 @@ describe Mnogootex::Job::Porter do
108
108
  it 'copies all source files' do
109
109
  subject.provide
110
110
  subject.target_dir.join('.mnogootex.src').unlink
111
- source_path.dirname.join('.mnogootex.yml').unlink
111
+ source_path.dirname.join('.mnogootexrc').unlink
112
112
  # NOTE: unlinking so comparison is easier to write
113
113
  expect(relative_subtree(source_path.dirname)).
114
114
  to eq(relative_subtree(subject.target_dir))
@@ -172,7 +172,7 @@ describe Mnogootex::Log::Processor do
172
172
 
173
173
  expect(my_processor.run(log.lines)).to eq(
174
174
  [" \e[0;33;49mHey, I'm warning you, dude. Stuff is gonna get bad.\e[0m\n",
175
- " \e[0;31;49mI warned you, dude. Here's an ERROR. :(\e[0m\n"]
175
+ " \e[0;31;49mI warned you, dude. Here's an ERROR. :(\e[0m\n"],
176
176
  )
177
177
  end
178
178
 
@@ -185,7 +185,7 @@ describe Mnogootex::Log::Processor do
185
185
 
186
186
  expect(my_processor.run(log.lines)).to eq(
187
187
  [" Hey, I'm warning you, dude. Stuff is gonna get bad.\n",
188
- " I warned you, dude. Here's an ERROR. :(\n"]
188
+ " I warned you, dude. Here's an ERROR. :(\n"],
189
189
  )
190
190
  end
191
191
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mnogootex
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paolo Brasolin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-06 00:00:00.000000000 Z
11
+ date: 2021-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -175,22 +175,26 @@ executables:
175
175
  extensions: []
176
176
  extra_rdoc_files: []
177
177
  files:
178
+ - ".github/actions/setup-ruby/action.yml"
178
179
  - ".github/workflows/main.yml"
179
180
  - ".gitignore"
180
181
  - ".rspec"
181
182
  - ".rubocop.yml"
183
+ - CHANGELOG.md
182
184
  - CODE_OF_CONDUCT.md
183
185
  - Gemfile
184
186
  - Guardfile
185
187
  - LICENSE.txt
186
188
  - README.md
187
189
  - Rakefile
190
+ - demo/.mnogootexrc
191
+ - demo/demo.asciicast
192
+ - demo/demo.gif
193
+ - demo/main.tex
188
194
  - exe/mnogootex
189
195
  - lib/mnogootex.rb
190
196
  - lib/mnogootex/cfg.rb
191
197
  - lib/mnogootex/cli.rb
192
- - lib/mnogootex/core_ext.rb
193
- - lib/mnogootex/defaults.yml
194
198
  - lib/mnogootex/job/logger.rb
195
199
  - lib/mnogootex/job/porter.rb
196
200
  - lib/mnogootex/job/runner.rb
@@ -202,7 +206,6 @@ files:
202
206
  - lib/mnogootex/log/matcher.rb
203
207
  - lib/mnogootex/log/matchers.yml
204
208
  - lib/mnogootex/log/processor.rb
205
- - lib/mnogootex/mnogoo.sh
206
209
  - lib/mnogootex/utils.rb
207
210
  - lib/mnogootex/version.rb
208
211
  - mnogootex.gemspec
@@ -212,7 +215,6 @@ files:
212
215
  - spec/mnogootex/log/processor_spec.rb
213
216
  - spec/mnogootex/utils_spec.rb
214
217
  - spec/spec_helper.rb
215
- - tty.gif
216
218
  homepage: https://github.com/tetrapharmakon/mnogootex
217
219
  licenses:
218
220
  - MIT
@@ -1,11 +0,0 @@
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
@@ -1,7 +0,0 @@
1
- # This is the default configuration file
2
- spinner: ⣾⣽⣻⢿⡿⣟⣯⣷
3
- commandline:
4
- - latexmk
5
- - -pdf
6
- - --interaction=nonstopmode
7
- work_path: null
@@ -1,21 +0,0 @@
1
- # Usage: source this in your bash profile as
2
- # [ -s "$(mnogootex mnogoo)" ] && . "$(mnogootex mnogoo)"
3
-
4
- mnogoo () {
5
- if [ "$1" = cd ]; then
6
- MN_PATH="$(IS_MNOGOO=true mnogootex dir "${@:2}")" || return
7
- cd "$MN_PATH" || exit
8
- elif [ "$1" = open ]; then
9
- MN_PATH="$(IS_MNOGOO=true mnogootex pdf "${@:2}")" || return
10
- if command -v open >/dev/null 2>&1; then
11
- printf '%s\n' "$MN_PATH" | while read -r line; do open "$line"; done
12
- elif command -v xdg-open >/dev/null 2>&1; then
13
- printf '%s\n' "$MN_PATH" | while read -r line; do xdg-open "$line"; done
14
- else
15
- echo "No known file opener (open, xdg-open) found on your system."
16
- echo "Please do chime in with suggestions: <paolo.brasolin@gmail.com>"
17
- fi
18
- else
19
- IS_MNOGOO=true mnogootex "$@"
20
- fi
21
- }
data/tty.gif DELETED
Binary file