mnogootex 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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