init project
This commit is contained in:
+31
@@ -0,0 +1,31 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file
|
||||
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
# v1.0.2
|
||||
## (2020-05-13)
|
||||
|
||||
* Update dependencies and replace yarn with npm [Paulo Castro]
|
||||
|
||||
# v1.0.1
|
||||
## (2020-05-02)
|
||||
|
||||
* Fix npm publish via balena CI [Paulo Castro]
|
||||
|
||||
# v1.0.0
|
||||
## (2020-04-29)
|
||||
|
||||
* Review README.md [Paulo Castro]
|
||||
|
||||
# v0.0.6
|
||||
## (2020-04-29)
|
||||
|
||||
* Update CI config (add .resinci.yml and appveyor.yml, remove codecov) [Paulo Castro]
|
||||
* Add LICENSE.md and CHANGELOG.md files (setup versionist) [Paulo Castro]
|
||||
* Update package.json (npm package details - fork from zeit/dockerignore) [Paulo Castro]
|
||||
|
||||
## 0.0.5 - 2019-04-22
|
||||
|
||||
* Last zeit/dockerignore release before fork as balena-io-modules/dockerignore
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
|
||||
* Copyright 2020 Balena Ltd. under the Apache 2.0 License included in this file.
|
||||
* Copyright 2018 Zeit Inc. under the MIT License included in this file.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
|
||||
# dockerignore
|
||||
|
||||
`dockerignore` is a file filter library fully compatible with Docker's [.dockerignore
|
||||
file](https://docs.docker.com/engine/reference/builder/#dockerignore-file), exposing the
|
||||
same API as the popular [ignore](https://github.com/kaelzhang/node-ignore) package for the
|
||||
`.gitignore` format.
|
||||
|
||||
`dockerignore` is also:
|
||||
|
||||
* Compatible with Linux, macOS and Windows.
|
||||
* Compact with 0 external dependencies (production install).
|
||||
* A pure Javascript port of Docker's Golang implementation of the `.dockerignore` format.
|
||||
* Well tested with hundreds of test cases including comparison against the actual behavior
|
||||
of `docker build` on Windows and Linux.
|
||||
* Relied on in production environments by
|
||||
[balena-cli](https://www.balena.io/docs/reference/balena-cli/),
|
||||
[now-cli](https://github.com/zeit/now-cli/)
|
||||
and other prominent projects built around Docker.
|
||||
|
||||
### What's different from `ignore`?
|
||||
|
||||
The `.dockerignore` spec has several differences from `.gitignore`:
|
||||
|
||||
- `*` in `.gitignore` matches everything, whereas in `.dockerignore` it only matches files in the
|
||||
current directory (like glob). This difference is important when whitelisting after a `*` rule.
|
||||
- `abc` in `.gitignore` matches all `abc` files and directories, however deeply nested, whereas
|
||||
in `.dockerignore` it matches only at `./abc` and not in subdirectories like `./somedir/abc`.
|
||||
- With `.gitignore`, when a parent directory is ignored, subdirectories cannot be re-added (using
|
||||
`!`) since `git` simply avoids walking through the subtree as an optimization. With
|
||||
`.dockerignore`, a subdirectory can be re-added even if a parent directory has been ignored.
|
||||
- For a complete list of differences, check out the [.gitignore
|
||||
spec](https://git-scm.com/docs/gitignore) and the [.dockerignore
|
||||
spec](https://docs.docker.com/engine/reference/builder/#dockerignore-file).
|
||||
|
||||
### What's the same as `ignore`?
|
||||
|
||||
The entire API. `dockerignore` started as a fork of
|
||||
[node-ignore](https://github.com/kaelzhang/node-ignore), and even reuses the same `index.d.ts` file
|
||||
for TypeScript definitions. Under the hood, `node-ignore`'s matching logic was rewritten to closely
|
||||
match Docker's implementation (modeled mainly around
|
||||
[dockerignore.go](https://github.com/moby/moby/blob/v19.03.8/builder/dockerignore/dockerignore.go)
|
||||
and [fileutils.go](https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go)).
|
||||
|
||||
### Compatibility
|
||||
|
||||
`dockerignore` works with Node.js version 8 and above, on Linux, macOS and Windows.
|
||||
The code is compiled with [Babel](https://babeljs.io/docs/en/).
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install --save @balena/dockerignore
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const ignore = require('@balena/dockerignore')
|
||||
const ig = ignore().add(['.abc/*', '!.abc/d/'])
|
||||
```
|
||||
|
||||
Typescript type definitions are also included:
|
||||
|
||||
```typescript
|
||||
import ignore from '@balena/dockerignore'
|
||||
const ig = ignore().add(['.abc/*', '!.abc/d/'])
|
||||
```
|
||||
|
||||
### Filter the given paths
|
||||
|
||||
```js
|
||||
const paths = [
|
||||
'.abc/a.js', // filtered out
|
||||
'.abc/d/e.js' // included
|
||||
]
|
||||
|
||||
ig.filter(paths) // ['.abc/d/e.js']
|
||||
ig.ignores('.abc/a.js') // true
|
||||
```
|
||||
|
||||
### As the filter function
|
||||
|
||||
```js
|
||||
paths.filter(ig.createFilter()); // ['.abc/d/e.js']
|
||||
```
|
||||
|
||||
### Windows paths are supported
|
||||
|
||||
```js
|
||||
ig.filter(['.abc\\a.js', '.abc\\d\\e.js'])
|
||||
// if the code above runs on windows, the result will be
|
||||
// ['.abc\\d\\e.js']
|
||||
```
|
||||
|
||||
## Backslashes _vs._ forward slashes
|
||||
|
||||
`dockerignore` behaves just like the Docker CLI ("docker build") in relation to the backslash (`\`)
|
||||
and forward slash (`/`) characters:
|
||||
|
||||
OS | Location | Slash (`/`) | Backslash (`\`)
|
||||
------------ | ----------------------- | ---------------| --------------------
|
||||
Linux, macOS | `.dockerignore` | Path separator | Escape character
|
||||
Linux, macOS | `filter()`, `ignores()` | Path separator | Part of file name
|
||||
Windows | `.dockerignore` | Path separator | Path separator
|
||||
Windows | `filter()`, `ignores()` | Path separator | Path separator
|
||||
|
||||
This means that forward slashes can be used in the `.dockerignore` file for cross-platform
|
||||
compatibility. This is consistent with how Windows works generally: both forward slashes
|
||||
and backslashes are accepted as path separators by the Command Prompt (cmd.exe) or
|
||||
PowerShell, and by library functions like the Golang
|
||||
[filepath.Clean](https://golang.org/pkg/path/filepath/#Clean) or the Node.js
|
||||
[path.normalize](https://nodejs.org/docs/latest-v10.x/api/path.html#path_path_normalize_path).
|
||||
|
||||
The use of the backslash as an escape character (Linux and macOS only) is not documented in the
|
||||
`.dockerignore` specification. "Reasonable" uses are probably to escape the few characters that
|
||||
have a special meaning in the `.dockerignore` file, namely `"*#!\"` (excluding the double quotes),
|
||||
as opposed to characters that have a special meaning in [regular
|
||||
expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
|
||||
generally. The "escaping" behavior for any other characters (e.g. `'\\b'`) is undefined and subject
|
||||
to implementation-specific interpretation that may change at any time.
|
||||
|
||||
## Absolute paths
|
||||
|
||||
Leading and trailing slashes (or backslashes on Windows) are removed from `.dockerignore` patterns,
|
||||
so `'/a'`, `'a/'` and `'/a/'` are all equivalent to `'a'` in a `.dockerignore` file, and they all
|
||||
anchor to the "leftmost" directory when matching against relative paths. For example, pattern `'a'`
|
||||
is compared with `'x'` for a given path `'x/y/z'`. This follows Docker's Golang implementation for
|
||||
compatibility. Conversely, a given absolute path will not match a non-wildcard pattern. More
|
||||
examples:
|
||||
|
||||
```js
|
||||
ignore().add('a').ignores('a') // true
|
||||
ignore().add('/a').ignores('a') // true
|
||||
ignore().add('/a/').ignores('a') // true
|
||||
ignore().add('a').ignores('/a') // false
|
||||
ignore().add('/a').ignores('/a') // false
|
||||
ignore().add('/a/').ignores('/a') // false
|
||||
```
|
||||
|
||||
Considering pattern slash removal, the cases above may be reduced to:
|
||||
|
||||
```js
|
||||
ignore().add('a').ignores('a') // true
|
||||
ignore().add('a').ignores('/a') // false
|
||||
```
|
||||
|
||||
The 'false' outcome for these examples may appear to mismatch the behavior of "docker build", when
|
||||
the source argument for the Dockerfile [ADD](https://docs.docker.com/engine/reference/builder/#add)
|
||||
or [COPY](https://docs.docker.com/engine/reference/builder/#copy) instructions is an absolute path
|
||||
(starting with a slash). The explanation is that docker converts absolute source paths to relative
|
||||
paths (relative to the "build context") **prior to pattern matching:**
|
||||
https://github.com/moby/moby/blob/v19.03.8/pkg/archive/archive.go#L806
|
||||
https://github.com/moby/moby/blob/v19.03.8/pkg/archive/archive.go#L825
|
||||
|
||||
... while `dockerignore` mirrors the implementation of the pattern matcher itself. The advice is
|
||||
for your application to do the same as the docker CLI: use relative paths for pattern matching.
|
||||
This is also generally more portable across different environments: development machine, CI
|
||||
pipelines, servers or end user devices.
|
||||
|
||||
## Comments
|
||||
|
||||
A pattern starting with `'#'` (hash) is ignored as a comment. The hash can be prefixed with
|
||||
a slash or backslash in order to match a file name that also starts with a hash:
|
||||
|
||||
```js
|
||||
ignore().add('#abc').ignores('#abc') // false
|
||||
ignore().add('/#abc').ignores('#abc') // true
|
||||
ignore().add('\\#abc').ignores('#abc') // true
|
||||
```
|
||||
|
||||
This works because of the leading slash removal from patterns described in [Absolute
|
||||
Paths](#absolute-paths).
|
||||
|
||||
## Exclusion patterns
|
||||
|
||||
Patterns starting with `'!'` (exclamation mark) define matching exclusions (exceptions) as
|
||||
documented in the [.dockerignore
|
||||
specification](https://docs.docker.com/engine/reference/builder/#dockerignore-file). For
|
||||
compatibility with Docker's implementation, patterns starting with `'/!'` or `'!/'` (but not
|
||||
`'/!/'`) will also be considered exclusion patterns, in addition to slash removal described in
|
||||
[Absolute Paths](#absolute-paths). Backslash escaping as `'\\!'` may be used in order to match a
|
||||
file or directory name that starts with the exclamation mark, but this is only possible on Linux
|
||||
and macOS, not on Windows. Again, it only behaves this way for compatibility with Docker's
|
||||
implementation.
|
||||
|
||||
## Options
|
||||
|
||||
Matching is case-insensitive by default, following the `ignore` API
|
||||
([ignorecase](https://www.npmjs.com/package/ignore#optionsignorecase-since-400)).
|
||||
Note however that Docker performs case-sensitive matching.
|
||||
Use the `ignorecase: false` option to align with Docker's behavior:
|
||||
|
||||
```js
|
||||
const ig = ignore({ ignorecase: false }) // for case-sensitive matching
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
### .add(pattern)
|
||||
### .add(patterns)
|
||||
|
||||
- **pattern** `String|Ignore` An ignore pattern string, or the `Ignore` instance
|
||||
- **patterns** `Array.<pattern>` Array of ignore patterns.
|
||||
|
||||
Adds a rule or several rules to the current manager.
|
||||
|
||||
Returns `this`
|
||||
|
||||
`pattern` could either be a line of ignore pattern or a string of multiple ignore patterns, which means we could just `ignore().add()` the content of a ignore file:
|
||||
|
||||
```js
|
||||
ignore()
|
||||
.add(fs.readFileSync(filenameOfGitignore).toString())
|
||||
.filter(filenames)
|
||||
```
|
||||
|
||||
`pattern` could also be an `ignore` instance, so that we could easily inherit the rules of another `Ignore` instance.
|
||||
|
||||
### .ignores(pathname)
|
||||
|
||||
Returns `Boolean` whether `pathname` should be ignored.
|
||||
|
||||
```js
|
||||
ig.ignores('.abc/a.js') // true
|
||||
```
|
||||
|
||||
### .filter(paths)
|
||||
|
||||
Filters the given array of pathnames, and returns the filtered array.
|
||||
|
||||
- **paths** `Array.<path>` The array of `pathname`s to be filtered.
|
||||
|
||||
### .createFilter()
|
||||
|
||||
Creates a filter function which could filter an array of paths with `Array.prototype.filter`.
|
||||
|
||||
Returns `function(path)` the filter function.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are always welcome!
|
||||
|
||||
1. Fork this repository to your own GitHub account and then clone it to your local device.
|
||||
2. Install the dependencies: `npm install`
|
||||
3. Add a test case (if applicable) and ensure it currently fails
|
||||
4. Add code to pass the test
|
||||
5. Make a pull request (additional tests will run on CI to ensure that your test case agrees with an actual `docker build`)
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
The initial work on this project was done by Pranay Prakash
|
||||
([@pranaygp](https://twitter.com/pranaygp)) / [▲ZEIT](https://zeit.co), Kael Zhang
|
||||
([@kaelzhang](https://github.com/kaelzhang)) and the [node-ignore
|
||||
contributors](https://github.com/kaelzhang/node-ignore/graphs/contributors).
|
||||
|
||||
Paulo Castro ([@pdcastro](https://github.com/pdcastro)) / [balena.io](https://www.balena.io/)
|
||||
forked the repository in year 2020 ([encouraged by
|
||||
Zeit](https://github.com/zeit/dockerignore/pull/16#issuecomment-611790479)) and put in a
|
||||
substantial effort on Windows support, cross-platform compatibility and testing, leading to release
|
||||
1.0.0.
|
||||
+363
@@ -0,0 +1,363 @@
|
||||
'use strict';
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2020 Balena Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* ------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright 2018 Zeit, Inc.
|
||||
* Licensed under the MIT License. See file LICENSE.md for a full copy.
|
||||
*
|
||||
* ------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* This module implements the [dockerignore
|
||||
* spec](https://docs.docker.com/engine/reference/builder/#dockerignore-file),
|
||||
* closely following Docker's (Moby) Golang implementation:
|
||||
* https://github.com/moby/moby/blob/v19.03.8/builder/dockerignore/dockerignore.go
|
||||
* https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go
|
||||
* https://github.com/moby/moby/blob/v19.03.8/pkg/archive/archive.go#L825
|
||||
*
|
||||
* Something the spec is not clear about, but we discovered by reading source code
|
||||
* and testing against the "docker build" command, is the handling of backslashes and
|
||||
* forward slashes as path separators and escape characters in the .dockerignore file
|
||||
* across platforms including Windows, Linux and macOS:
|
||||
*
|
||||
* * On Linux and macOS, only forward slashes can be used as path separators in the
|
||||
* .dockerignore file, and the backslash works as an escape character.
|
||||
* * On Windows, both forward slashes and backslashes are allowed as path separators
|
||||
* in the .dockerignore file, and the backslash is not used as an escape character.
|
||||
*
|
||||
* This is consistent with how Windows works generally: both forward slashes and
|
||||
* backslashes are accepted as path separators by the cmd.exe Command Prompt or
|
||||
* PowerShell, and by library functions like the Golang filepath.Clean or the
|
||||
* Node.js path.normalize.
|
||||
*
|
||||
* Similarly, path strings provided to the IgnoreBase.ignores() and IgnoreBase.filter()
|
||||
* methods can use either forward slashes or backslashes as path separators on Windows,
|
||||
* but only forward slashes are accepted as path separators on Linux and macOS.
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
|
||||
const factory = options => new IgnoreBase(options); // https://github.com/kaelzhang/node-ignore/blob/5.1.4/index.js#L538-L539
|
||||
// Fixes typescript module import
|
||||
|
||||
|
||||
factory.default = factory;
|
||||
module.exports = factory;
|
||||
|
||||
function make_array(subject) {
|
||||
return Array.isArray(subject) ? subject : [subject];
|
||||
}
|
||||
|
||||
const REGEX_TRAILING_SLASH = /(?<=.)\/$/;
|
||||
const REGEX_TRAILING_BACKSLASH = /(?<=.)\\$/;
|
||||
const REGEX_TRAILING_PATH_SEP = path.sep === '\\' ? REGEX_TRAILING_BACKSLASH : REGEX_TRAILING_SLASH;
|
||||
const KEY_IGNORE = typeof Symbol !== 'undefined' ? Symbol.for('dockerignore') : 'dockerignore'; // An implementation of Go's filepath.Clean
|
||||
// https://golang.org/pkg/path/filepath/#Clean
|
||||
// https://github.com/golang/go/blob/master/src/path/filepath/path.go
|
||||
// Note that, like Go, on Windows this function converts forward slashes
|
||||
// to backslashes.
|
||||
|
||||
function cleanPath(file) {
|
||||
return path.normalize(file).replace(REGEX_TRAILING_PATH_SEP, '');
|
||||
} // Javascript port of Golang's filepath.ToSlash
|
||||
// https://golang.org/pkg/path/filepath/#ToSlash
|
||||
// https://github.com/golang/go/blob/master/src/path/filepath/path.go
|
||||
// Convert any OS-specific path separator to '/'. Backslash is converted
|
||||
// to forward slash on Windows, but not on Linux/macOS.
|
||||
// Note that both forward slashes and backslashes are valid path separators on
|
||||
// Windows. As a result, code such as `pattern.split(path.sep).join('/')` fails
|
||||
// on Windows when forward slashes are used as path separators.
|
||||
|
||||
|
||||
function toSlash(file) {
|
||||
if (path.sep === '/') {
|
||||
return file;
|
||||
}
|
||||
|
||||
return file.replace(/\\/g, '/');
|
||||
} // Javascript port of Golang's filepath.FromSlash
|
||||
// https://github.com/golang/go/blob/master/src/path/filepath/path.go
|
||||
|
||||
|
||||
function fromSlash(file) {
|
||||
if (path.sep === '/') {
|
||||
return file;
|
||||
}
|
||||
|
||||
return file.replace(/\//g, path.sep);
|
||||
}
|
||||
|
||||
class IgnoreBase {
|
||||
constructor({
|
||||
// https://github.com/kaelzhang/node-ignore/blob/5.1.4/index.js#L372
|
||||
ignorecase = true
|
||||
} = {}) {
|
||||
this._rules = [];
|
||||
this._ignorecase = ignorecase;
|
||||
this[KEY_IGNORE] = true;
|
||||
|
||||
this._initCache();
|
||||
}
|
||||
|
||||
_initCache() {
|
||||
this._cache = {};
|
||||
} // @param {Array.<string>|string|Ignore} pattern
|
||||
|
||||
|
||||
add(pattern) {
|
||||
this._added = false;
|
||||
|
||||
if (typeof pattern === 'string') {
|
||||
pattern = pattern.split(/\r?\n/g);
|
||||
}
|
||||
|
||||
make_array(pattern).forEach(this._addPattern, this); // Some rules have just added to the ignore,
|
||||
// making the behavior changed.
|
||||
|
||||
if (this._added) {
|
||||
this._initCache();
|
||||
}
|
||||
|
||||
return this;
|
||||
} // legacy
|
||||
|
||||
|
||||
addPattern(pattern) {
|
||||
return this.add(pattern);
|
||||
}
|
||||
|
||||
_addPattern(pattern) {
|
||||
// https://github.com/kaelzhang/node-ignore/issues/32
|
||||
if (pattern && pattern[KEY_IGNORE]) {
|
||||
this._rules = this._rules.concat(pattern._rules);
|
||||
this._added = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._checkPattern(pattern)) {
|
||||
const rule = this._createRule(pattern.trim());
|
||||
|
||||
if (rule !== null) {
|
||||
this._added = true;
|
||||
|
||||
this._rules.push(rule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_checkPattern(pattern) {
|
||||
// https://github.com/moby/moby/blob/v19.03.8/builder/dockerignore/dockerignore.go#L34-L40
|
||||
return pattern && typeof pattern === 'string' && pattern.indexOf('#') !== 0 && pattern.trim() !== "";
|
||||
}
|
||||
|
||||
filter(paths) {
|
||||
return make_array(paths).filter(path => this._filter(path));
|
||||
}
|
||||
|
||||
createFilter() {
|
||||
return path => this._filter(path);
|
||||
}
|
||||
|
||||
ignores(path) {
|
||||
return !this._filter(path);
|
||||
} // https://github.com/moby/moby/blob/v19.03.8/builder/dockerignore/dockerignore.go#L41-L53
|
||||
// https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L29-L55
|
||||
|
||||
|
||||
_createRule(pattern) {
|
||||
const origin = pattern;
|
||||
let negative = false; // > An optional prefix "!" which negates the pattern;
|
||||
// https://github.com/moby/moby/blob/v19.03.8/builder/dockerignore/dockerignore.go#L43-L46
|
||||
|
||||
if (pattern[0] === '!') {
|
||||
negative = true;
|
||||
pattern = pattern.substring(1).trim();
|
||||
} // https://github.com/moby/moby/blob/v19.03.8/builder/dockerignore/dockerignore.go#L47-L53
|
||||
|
||||
|
||||
if (pattern.length > 0) {
|
||||
pattern = cleanPath(pattern);
|
||||
pattern = toSlash(pattern);
|
||||
|
||||
if (pattern.length > 1 && pattern[0] === '/') {
|
||||
pattern = pattern.slice(1);
|
||||
}
|
||||
} // https://github.com/moby/moby/blob/v19.03.8/builder/dockerignore/dockerignore.go#L54-L55
|
||||
|
||||
|
||||
if (negative) {
|
||||
pattern = '!' + pattern;
|
||||
} // https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L30
|
||||
|
||||
|
||||
pattern = pattern.trim();
|
||||
|
||||
if (pattern === "") {
|
||||
return null;
|
||||
} // https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L34
|
||||
// convert forward slashes to backslashes on Windows
|
||||
|
||||
|
||||
pattern = cleanPath(pattern); // https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L36-L42
|
||||
|
||||
if (pattern[0] === '!') {
|
||||
if (pattern.length === 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
negative = true;
|
||||
pattern = pattern.substring(1);
|
||||
} else {
|
||||
negative = false;
|
||||
}
|
||||
|
||||
return {
|
||||
origin,
|
||||
pattern,
|
||||
// https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L54
|
||||
dirs: pattern.split(path.sep),
|
||||
negative
|
||||
};
|
||||
} // @returns `Boolean` true if the `path` is NOT ignored
|
||||
|
||||
|
||||
_filter(path) {
|
||||
if (!path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (path in this._cache) {
|
||||
return this._cache[path];
|
||||
}
|
||||
|
||||
return this._cache[path] = this._test(path);
|
||||
} // @returns {Boolean} true if a file is NOT ignored
|
||||
// https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L62
|
||||
|
||||
|
||||
_test(file) {
|
||||
file = fromSlash(file); // equivalent to golang filepath.Dir() https://golang.org/src/path/filepath/path.go
|
||||
|
||||
const parentPath = cleanPath(path.dirname(file));
|
||||
const parentPathDirs = parentPath.split(path.sep);
|
||||
let matched = false;
|
||||
|
||||
this._rules.forEach(rule => {
|
||||
let match = this._match(file, rule); // https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L80
|
||||
|
||||
|
||||
if (!match && parentPath !== ".") {
|
||||
// Check to see if the pattern matches one of our parent dirs.
|
||||
if (rule.dirs.includes('**')) {
|
||||
// Ah shucks! We have to test every possible parent path that has
|
||||
// a number of dirs _n_ where
|
||||
// `rule.dirs.filter(doubleStar).length <= _n_ <= parentPathDirs.length`
|
||||
// since the ** can imply any number of directories including 0
|
||||
for (let i = rule.dirs.filter(x => x !== '**').length; i <= parentPathDirs.length; i++) {
|
||||
match = match || this._match(parentPathDirs.slice(0, i).join(path.sep), rule);
|
||||
}
|
||||
} else if (rule.dirs.length <= parentPathDirs.length) {
|
||||
// https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L83
|
||||
match = this._match(parentPathDirs.slice(0, rule.dirs.length).join(path.sep), rule);
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
matched = !rule.negative;
|
||||
}
|
||||
});
|
||||
|
||||
return !matched;
|
||||
} // @returns {Boolean} true if a file is matched by a rule
|
||||
|
||||
|
||||
_match(file, rule) {
|
||||
return this._compile(rule).regexp.test(file);
|
||||
} // https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L139
|
||||
|
||||
|
||||
_compile(rule) {
|
||||
if (rule.regexp) {
|
||||
return rule;
|
||||
}
|
||||
|
||||
let regStr = '^'; // Go through the pattern and convert it to a regexp.
|
||||
|
||||
let escapedSlash = path.sep === '\\' ? '\\\\' : path.sep;
|
||||
|
||||
for (let i = 0; i < rule.pattern.length; i++) {
|
||||
const ch = rule.pattern[i];
|
||||
|
||||
if (ch === '*') {
|
||||
if (rule.pattern[i + 1] === '*') {
|
||||
// is some flavor of "**"
|
||||
i++; // Treat **/ as ** so eat the "/"
|
||||
|
||||
if (rule.pattern[i + 1] === path.sep) {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (rule.pattern[i + 1] === undefined) {
|
||||
// is "**EOF" - to align with .gitignore just accept all
|
||||
regStr += ".*";
|
||||
} else {
|
||||
// is "**"
|
||||
// Note that this allows for any # of /'s (even 0) because
|
||||
// the .* will eat everything, even /'s
|
||||
regStr += `(.*${escapedSlash})?`;
|
||||
}
|
||||
} else {
|
||||
// is "*" so map it to anything but "/"
|
||||
regStr += `[^${escapedSlash}]*`;
|
||||
}
|
||||
} else if (ch === '?') {
|
||||
// "?" is any char except "/"
|
||||
regStr += `[^${escapedSlash}]`;
|
||||
} else if (ch === '.' || ch === '$') {
|
||||
// Escape some regexp special chars that have no meaning
|
||||
// in golang's filepath.Match
|
||||
regStr += `\\${ch}`;
|
||||
} else if (ch === '\\') {
|
||||
// escape next char. Note that a trailing \ in the pattern
|
||||
// will be left alone (but need to escape it)
|
||||
if (path.sep === '\\') {
|
||||
// On windows map "\" to "\\", meaning an escaped backslash,
|
||||
// and then just continue because filepath.Match on
|
||||
// Windows doesn't allow escaping at all
|
||||
regStr += escapedSlash;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rule.pattern[i + 1] !== undefined) {
|
||||
regStr += '\\' + rule.pattern[i + 1];
|
||||
i++;
|
||||
} else {
|
||||
regStr += '\\';
|
||||
}
|
||||
} else {
|
||||
regStr += ch;
|
||||
}
|
||||
}
|
||||
|
||||
regStr += "$";
|
||||
rule.regexp = new RegExp(regStr, this._ignorecase ? 'i' : '');
|
||||
return rule;
|
||||
}
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
export interface Ignore {
|
||||
/**
|
||||
* Adds a rule rules to the current manager.
|
||||
* @param {string | Ignore} pattern
|
||||
* @returns IgnoreBase
|
||||
*/
|
||||
add(pattern: string | Ignore): Ignore
|
||||
/**
|
||||
* Adds several rules to the current manager.
|
||||
* @param {string[]} patterns
|
||||
* @returns IgnoreBase
|
||||
*/
|
||||
add(patterns: (string | Ignore)[]): Ignore
|
||||
|
||||
/**
|
||||
* Filters the given array of pathnames, and returns the filtered array.
|
||||
* NOTICE that each path here should be a relative path to the root of your repository.
|
||||
* @param paths the array of paths to be filtered.
|
||||
* @returns The filtered array of paths
|
||||
*/
|
||||
filter(paths: string[]): string[]
|
||||
/**
|
||||
* Creates a filter function which could filter
|
||||
* an array of paths with Array.prototype.filter.
|
||||
*/
|
||||
createFilter(): (path: string) => boolean
|
||||
|
||||
/**
|
||||
* Returns Boolean whether pathname should be ignored.
|
||||
* @param {string} pathname a path to check
|
||||
* @returns boolean
|
||||
*/
|
||||
ignores(pathname: string): boolean
|
||||
}
|
||||
|
||||
interface Options {
|
||||
ignorecase?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new ignore manager.
|
||||
*/
|
||||
declare function ignore(options?: Options): Ignore
|
||||
|
||||
export default ignore
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "@balena/dockerignore",
|
||||
"version": "1.0.2",
|
||||
"description": "dockerignore is a file filter library compatible with Docker and the node-ignore API",
|
||||
"main": "./ignore.js",
|
||||
"files": [
|
||||
"ignore.js",
|
||||
"index.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"prepublishOnly": "npm run build",
|
||||
"build": "babel -o ignore.js index.js",
|
||||
"test": "npm run build && nyc ava ./test/ignore.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:balena-io-modules/dockerignore.git"
|
||||
},
|
||||
"keywords": [
|
||||
"ignore",
|
||||
".dockerignore",
|
||||
"dockerignore",
|
||||
"rules",
|
||||
"manager",
|
||||
"filter",
|
||||
"regexp",
|
||||
"regex",
|
||||
"fnmatch",
|
||||
"glob",
|
||||
"asterisks",
|
||||
"regular-expression"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/balena-io-modules/dockerignore/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"async-sema": "^3.1.0",
|
||||
"ava": "^0.25.0",
|
||||
"@babel/cli": "^7.8.4",
|
||||
"@babel/preset-env": "^7.9.6",
|
||||
"chai": "^4.2.0",
|
||||
"cuid": "^2.1.8",
|
||||
"mkdirp": "^1.0.4",
|
||||
"nyc": "^15.0.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"tmp": "^0.2.1"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user