├── .editorconfig
├── .eslintrc.json
├── .gitattributes
├── .gitignore
├── .travis.yml
├── .verb.md
├── LICENSE
├── README.md
├── docs
└── demo.gif
├── generator.js
├── index.js
├── lib
├── backup.js
└── extract.js
├── package.json
└── test
├── fixtures
└── foo
│ ├── .editorconfig
│ ├── .eslintrc.json
│ ├── .gitattributes
│ ├── .gitignore
│ ├── .travis.yml
│ ├── LICENSE
│ ├── README.md
│ ├── contributing.md
│ ├── index.js
│ └── package.json
├── plugin.js
└── test.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 |
10 | [*.md]
11 | trim_trailing_whitespace = false
12 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "ecmaFeatures": {
3 | "modules": true,
4 | "experimentalObjectRestSpread": true
5 | },
6 | "env": {
7 | "browser": false,
8 | "es6": true,
9 | "node": true,
10 | "mocha": true
11 | },
12 | "globals": {
13 | "document": false,
14 | "navigator": false,
15 | "window": false
16 | },
17 | "rules": {
18 | "accessor-pairs": 2,
19 | "arrow-spacing": [
20 | 2,
21 | {
22 | "before": true,
23 | "after": true
24 | }
25 | ],
26 | "block-spacing": [
27 | 2,
28 | "always"
29 | ],
30 | "brace-style": [
31 | 2,
32 | "1tbs",
33 | {
34 | "allowSingleLine": true
35 | }
36 | ],
37 | "comma-dangle": [
38 | 2,
39 | "never"
40 | ],
41 | "comma-spacing": [
42 | 2,
43 | {
44 | "before": false,
45 | "after": true
46 | }
47 | ],
48 | "comma-style": [
49 | 2,
50 | "last"
51 | ],
52 | "constructor-super": 2,
53 | "curly": [
54 | 2,
55 | "multi-line"
56 | ],
57 | "dot-location": [
58 | 2,
59 | "property"
60 | ],
61 | "eol-last": 2,
62 | "eqeqeq": [
63 | 2,
64 | "allow-null"
65 | ],
66 | "generator-star-spacing": [
67 | 2,
68 | {
69 | "before": true,
70 | "after": true
71 | }
72 | ],
73 | "handle-callback-err": [
74 | 2,
75 | "^(err|error)$"
76 | ],
77 | "indent": [
78 | 2,
79 | 2,
80 | {
81 | "SwitchCase": 1
82 | }
83 | ],
84 | "key-spacing": [
85 | 2,
86 | {
87 | "beforeColon": false,
88 | "afterColon": true
89 | }
90 | ],
91 | "keyword-spacing": [
92 | 2,
93 | {
94 | "before": true,
95 | "after": true
96 | }
97 | ],
98 | "new-cap": [
99 | 2,
100 | {
101 | "newIsCap": true,
102 | "capIsNew": false
103 | }
104 | ],
105 | "new-parens": 2,
106 | "no-array-constructor": 2,
107 | "no-caller": 2,
108 | "no-class-assign": 2,
109 | "no-cond-assign": 2,
110 | "no-const-assign": 2,
111 | "no-control-regex": 2,
112 | "no-debugger": 2,
113 | "no-delete-var": 2,
114 | "no-dupe-args": 2,
115 | "no-dupe-class-members": 2,
116 | "no-dupe-keys": 2,
117 | "no-duplicate-case": 2,
118 | "no-empty-character-class": 2,
119 | "no-eval": 2,
120 | "no-ex-assign": 2,
121 | "no-extend-native": 2,
122 | "no-extra-bind": 2,
123 | "no-extra-boolean-cast": 2,
124 | "no-extra-parens": [
125 | 2,
126 | "functions"
127 | ],
128 | "no-fallthrough": 2,
129 | "no-floating-decimal": 2,
130 | "no-func-assign": 2,
131 | "no-implied-eval": 2,
132 | "no-inner-declarations": [
133 | 2,
134 | "functions"
135 | ],
136 | "no-invalid-regexp": 2,
137 | "no-irregular-whitespace": 2,
138 | "no-iterator": 2,
139 | "no-label-var": 2,
140 | "no-labels": 2,
141 | "no-lone-blocks": 2,
142 | "no-mixed-spaces-and-tabs": 2,
143 | "no-multi-spaces": 2,
144 | "no-multi-str": 2,
145 | "no-multiple-empty-lines": [
146 | 2,
147 | {
148 | "max": 1
149 | }
150 | ],
151 | "no-native-reassign": 0,
152 | "no-negated-in-lhs": 2,
153 | "no-new": 2,
154 | "no-new-func": 2,
155 | "no-new-object": 2,
156 | "no-new-require": 2,
157 | "no-new-wrappers": 2,
158 | "no-obj-calls": 2,
159 | "no-octal": 2,
160 | "no-octal-escape": 2,
161 | "no-proto": 0,
162 | "no-redeclare": 2,
163 | "no-regex-spaces": 2,
164 | "no-return-assign": 2,
165 | "no-self-compare": 2,
166 | "no-sequences": 2,
167 | "no-shadow-restricted-names": 2,
168 | "no-spaced-func": 2,
169 | "no-sparse-arrays": 2,
170 | "no-this-before-super": 2,
171 | "no-throw-literal": 2,
172 | "no-trailing-spaces": 0,
173 | "no-undef": 2,
174 | "no-undef-init": 2,
175 | "no-unexpected-multiline": 2,
176 | "no-unneeded-ternary": [
177 | 2,
178 | {
179 | "defaultAssignment": false
180 | }
181 | ],
182 | "no-unreachable": 2,
183 | "no-unused-vars": [
184 | 2,
185 | {
186 | "vars": "all",
187 | "args": "none"
188 | }
189 | ],
190 | "no-useless-call": 0,
191 | "no-with": 2,
192 | "one-var": [
193 | 0,
194 | {
195 | "initialized": "never"
196 | }
197 | ],
198 | "operator-linebreak": [
199 | 0,
200 | "after",
201 | {
202 | "overrides": {
203 | "?": "before",
204 | ":": "before"
205 | }
206 | }
207 | ],
208 | "padded-blocks": [
209 | 0,
210 | "never"
211 | ],
212 | "quotes": [
213 | 2,
214 | "single",
215 | "avoid-escape"
216 | ],
217 | "radix": 2,
218 | "semi": [
219 | 2,
220 | "always"
221 | ],
222 | "semi-spacing": [
223 | 2,
224 | {
225 | "before": false,
226 | "after": true
227 | }
228 | ],
229 | "space-before-blocks": [
230 | 2,
231 | "always"
232 | ],
233 | "space-before-function-paren": [
234 | 2,
235 | "never"
236 | ],
237 | "space-in-parens": [
238 | 2,
239 | "never"
240 | ],
241 | "space-infix-ops": 2,
242 | "space-unary-ops": [
243 | 2,
244 | {
245 | "words": true,
246 | "nonwords": false
247 | }
248 | ],
249 | "spaced-comment": [
250 | 0,
251 | "always",
252 | {
253 | "markers": [
254 | "global",
255 | "globals",
256 | "eslint",
257 | "eslint-disable",
258 | "*package",
259 | "!",
260 | ","
261 | ]
262 | }
263 | ],
264 | "use-isnan": 2,
265 | "valid-typeof": 2,
266 | "wrap-iife": [
267 | 2,
268 | "any"
269 | ],
270 | "yoda": [
271 | 2,
272 | "never"
273 | ]
274 | }
275 | }
276 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | coverage
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - "node"
5 | - "6"
6 | - "5"
7 | - "4"
8 | - "0.12"
9 | - "0.10"
10 | matrix:
11 | fast_finish: true
12 | allow_failures:
13 | - node_js: "4"
14 | - node_js: "0.10"
15 | - node_js: "0.12"
16 |
--------------------------------------------------------------------------------
/.verb.md:
--------------------------------------------------------------------------------
1 | ## Usage
2 |
3 | ### CLI
4 |
5 | When installed globally, the `backup` generator is available to use through the `gen` command:
6 |
7 | Backup a folder to a tar file using the [default](#default) task.
8 |
9 | ```sh
10 | $ gen backup --src my-project --dest /backups/my-project
11 | ```
12 |
13 | Extract a tar file to a folder using the [extract](#extract) task.
14 |
15 | ```sh
16 | $ gen backup:extract --src /backups/my-project/2017-01-02.tar --dest my-project-2
17 | ```
18 | ### API
19 |
20 | **Params**
21 |
22 | * `app` **{Object}**: [generate](https://github.com/generate/generate) instance to add tasks to.
23 |
24 | **Example**
25 |
26 | ```js
27 | // use as a plugin with existing generate instance
28 | // $ gen backup
29 | app.use(require('generate-backup'));
30 |
31 | // use as a subgenerator on an existing generate instance
32 | // $ gen bkp
33 | app.register('bkp', require('generate-backup'));
34 | ```
35 |
36 |
37 | ### Internal API
38 |
39 | Internal functions that are used inside the tasks to provide [backup](#backup) and [extract](#extract) functionality.
40 |
41 | {%= apidocs('lib/*.js') %}
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Brian Woodward
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Create backup archives with generate.
9 |
10 | # generate-backup
11 |
12 | [](https://www.npmjs.com/package/generate-backup) [](https://npmjs.org/package/generate-backup) [](https://travis-ci.org/generate/generate-backup)
13 |
14 | 
15 |
16 | ## Usage
17 |
18 | ### CLI
19 |
20 | When installed globally, the `backup` generator is available to use through the `gen` command:
21 |
22 | Backup a folder to a tar file using the [default](#default) task.
23 |
24 | ```sh
25 | $ gen backup --src my-project --dest /backups/my-project
26 | ```
27 |
28 | Extract a tar file to a folder using the [extract](#extract) task.
29 |
30 | ```sh
31 | $ gen backup:extract --src /backups/my-project/2017-01-02.tar --dest my-project-2
32 | ```
33 |
34 | ### API
35 |
36 | **Params**
37 |
38 | * `app` **{Object}**: [generate](https://github.com/generate/generate) instance to add tasks to.
39 |
40 | **Example**
41 |
42 | ```js
43 | // use as a plugin with existing generate instance
44 | // $ gen backup
45 | app.use(require('generate-backup'));
46 |
47 | // use as a subgenerator on an existing generate instance
48 | // $ gen bkp
49 | app.register('bkp', require('generate-backup'));
50 | ```
51 |
52 | ### Internal API
53 |
54 | Internal functions that are used inside the tasks to provide [backup](#backup) and [extract](#extract) functionality.
55 |
56 | **Params**
57 |
58 | * `options` **{Object}**: Options to control what is archived.
59 | * `returns` **{Stream}**: The stream created by [tar-fs](https://github.com/mafintosh/tar-fs).
60 |
61 | **Example**
62 |
63 | ```js
64 | backup({src: './', dest: '/backups'});
65 | ```
66 |
67 | **Params**
68 |
69 | * `options` **{Object}**: Options to control what is extracted.
70 | * `returns` **{Stream}**: The stream created by [tar-fs](https://github.com/mafintosh/tar-fs).
71 |
72 | **Example**
73 |
74 | ```js
75 | extract({src: '/backups/2017-01-02.tar', dest: './'});
76 | ```
77 |
78 | ## What is "Generate"?
79 |
80 | Generate is a command line tool and developer framework for scaffolding out new GitHub projects using [generators](https://github.com/generate/generate/blob/master/docs/generators.md) and [tasks](https://github.com/generate/generate/blob/master/docs/tasks.md).
81 |
82 | Answers to prompts and the user's environment can be used to determine the templates, directories, files and contents to build. Support for [gulp](http://gulpjs.com), [base](https://github.com/node-base/base) and [assemble](https://github.com/assemble/assemble) plugins, and much more.
83 |
84 | **For more information**:
85 |
86 | * Visit the [generate project](https://github.com/generate/generate/)
87 | * Visit the [generate documentation](https://github.com/generate/generate/blob/master/docs/)
88 | * Find [generators on npm](https://www.npmjs.com/browse/keyword/generate-generator) (help us [author generators](https://github.com/generate/generate/blob/master/docs/micro-generators.md))
89 |
90 | ## Getting started
91 |
92 | ### Install
93 |
94 | **Installing the CLI**
95 |
96 | To run the `backup` generator from the command line, you'll need to install [Generate](https://github.com/generate/generate) globally first. You can do that now with the following command:
97 |
98 | ```sh
99 | $ npm install --global generate
100 | ```
101 |
102 | This adds the `gen` command to your system path, allowing it to be run from any directory.
103 |
104 | **Install generate-backup**
105 |
106 | Install this module with the following command:
107 |
108 | ```sh
109 | $ npm install --global generate-backup
110 | ```
111 |
112 | ### Usage
113 |
114 | Run this generator's `default` [task](https://github.com/generate/generate/blob/master/docs/tasks.md#default) with the following command:
115 |
116 | ```sh
117 | $ gen backup
118 | ```
119 |
120 | **What you should see in the terminal**
121 |
122 | If completed successfully, you should see both `starting` and `finished` events in the terminal, like the following:
123 |
124 | ```sh
125 | [00:44:21] starting ...
126 | ...
127 | [00:44:22] finished ✔
128 | ```
129 |
130 | If you do not see one or both of those events, please [let us know about it](../../issues).
131 |
132 | ### Help
133 |
134 | To see a general help menu and available commands for Generate's CLI, run:
135 |
136 | ```sh
137 | $ gen help
138 | ```
139 |
140 | ## Tasks
141 |
142 | All available tasks.
143 |
144 | ### [backup](generator.js#L41)
145 |
146 | Default `backup` task that will backup the specified `--src` folder a `.tar` file in the specified `--dest` folder using an optional `--ignore` flag.
147 |
148 | **remove spaces in the ignore pattern**
149 |
150 | **Example**
151 |
152 | ```sh
153 | # backup all node projects to the /backups/projects folder but ignore any node_modules folders
154 | $ gen backup --dest /backups/projects --src projects --ignore '** /node_modules/{,** /*}'
155 | ```
156 |
157 | ### [extract](generator.js#L59)
158 |
159 | `extract` task that will extract the files from the specified `--src` `.tar` file to the specified `--dest` folder using an optional `--ignore` flag.
160 |
161 | **Example**
162 |
163 | ```sh
164 | # extract the archived projects from /backups/projects/2017-01-02.tar to the ./restore/projects folder.
165 | $ gen backup --dest restore/projects --src /backups/projects/2017-01-02.tar
166 | ```
167 |
168 | ### [default](generator.js#L71)
169 |
170 | Default task aliased for [backup](#backup)
171 |
172 | Visit Generate's [documentation for tasks](https://github.com/generate/generate/blob/master/docs/tasks.md).
173 |
174 | ## Next steps
175 |
176 | ### Running unit tests
177 |
178 | It's never too early to begin running unit tests. When you're ready to get started, the following command will ensure the project's dependencies are installed then run all of the unit tests:
179 |
180 | ```sh
181 | $ npm install && test
182 | ```
183 |
184 | ### Publishing your generator
185 |
186 | If you're tests are passing and you're ready to publish your generator to [npm](https://www.npmjs.com), you can do that now with the following command:
187 |
188 | **Are you sure you're ready?!**
189 |
190 | Let's go!
191 |
192 | ```sh
193 | $ npm publish
194 | ```
195 |
196 | ## About
197 |
198 | ### Related projects
199 |
200 | * [generate](https://www.npmjs.com/package/generate): Command line tool and developer framework for scaffolding out new GitHub projects. Generate offers the… [more](https://github.com/generate/generate) | [homepage](https://github.com/generate/generate "Command line tool and developer framework for scaffolding out new GitHub projects. Generate offers the robustness and configurability of Yeoman, the expressiveness and simplicity of Slush, and more powerful flow control and composability than either.")
201 | * [micromatch](https://www.npmjs.com/package/micromatch): Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch. | [homepage](https://github.com/jonschlinkert/micromatch "Glob matching for javascript/node.js. A drop-in replacement and faster alternative to minimatch and multimatch.")
202 | * [tar-fs](https://www.npmjs.com/package/tar-fs): filesystem bindings for tar-stream | [homepage](https://github.com/mafintosh/tar-fs "filesystem bindings for tar-stream")
203 |
204 | ### Community
205 |
206 | Are you using [Generate](https://github.com/generate/generate) in your project? Have you published a [generator](https://github.com/generate/generate/blob/master/docs/generators.md) and want to share your project with the world?
207 |
208 | Here are some suggestions!
209 |
210 | * If you get like Generate and want to tweet about it, please feel free to mention `@generatejs` or use the `#generatejs` hashtag
211 | * Show your love by starring [Generate](https://github.com/generate/generate) and `generate-backup`
212 | * Get implementation help on [StackOverflow](http://stackoverflow.com/questions/tagged/generate) (please use the `generatejs` tag in questions)
213 | * **Gitter** Discuss Generate with us on [Gitter](https://gitter.im/generate/generate)
214 | * If you publish an generator, thank you! To make your project as discoverable as possible, please add the keyword `generategenerator` to package.json.
215 |
216 | ### Contributing
217 |
218 | Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).
219 |
220 | ### Running tests
221 |
222 | Install dev dependencies:
223 |
224 | ```sh
225 | $ npm install -d && npm test
226 | ```
227 |
228 | ### Author
229 |
230 | **Brian Woodward**
231 |
232 | * [github/doowb](https://github.com/doowb)
233 | * [twitter/doowb](http://twitter.com/doowb)
234 |
235 | ### License
236 |
237 | Copyright © 2017, [Brian Woodward](https://github.com/doowb).
238 | Released under the [MIT license](LICENSE).
239 |
240 | ***
241 |
242 | _This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.2.3, on January 02, 2017._
--------------------------------------------------------------------------------
/docs/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/generate/generate-backup/5847e8760b3a8601e3568b7ee752c9b2ac522c5e/docs/demo.gif
--------------------------------------------------------------------------------
/generator.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var isValid = require('is-valid-app');
4 | var backup = require('./lib/backup');
5 | var extract = require('./lib/extract');
6 |
7 | /**
8 | * [generate][] plugin or subgenerator that adds a [backup](#backup) and [extract](#extract) tasks for archiving and extract tar archives.
9 | * Advantages of using this generator include being able to specify complex ignore patterns (handled by [micromatch][]).
10 | *
11 | * ```js
12 | * // use as a plugin with existing generate instance
13 | * // $ gen backup
14 | * app.use(require('generate-backup'));
15 | *
16 | * // use as a subgenerator on an existing generate instance
17 | * // $ gen bkp
18 | * app.register('bkp', require('generate-backup'));
19 | * ```
20 | *
21 | * @param {Object} `app` [generate][] instance to add tasks to.
22 | */
23 |
24 | module.exports = function(app) {
25 | if (!isValid(app, 'generate-backup')) return;
26 |
27 | /**
28 | * Default `backup` task that will backup the specified `--src` folder a `.tar` file in the specified `--dest` folder
29 | * using an optional `--ignore` flag.
30 | *
31 | * __remove spaces in the ignore pattern__
32 | *
33 | * ```sh
34 | * # backup all node projects to the /backups/projects folder but ignore any node_modules folders
35 | * $ gen backup --dest /backups/projects --src projects --ignore '** /node_modules/{,** /*}'
36 | * ```
37 | * @name backup
38 | * @api public
39 | */
40 |
41 | app.task('backup', function(cb) {
42 | backup(app.options)
43 | .once('error', cb)
44 | .once('finish', cb);
45 | });
46 |
47 | /**
48 | * `extract` task that will extract the files from the specified `--src` `.tar` file to the specified `--dest` folder
49 | * using an optional `--ignore` flag.
50 | *
51 | * ```sh
52 | * # extract the archived projects from /backups/projects/2017-01-02.tar to the ./restore/projects folder.
53 | * $ gen backup --dest restore/projects --src /backups/projects/2017-01-02.tar
54 | * ```
55 | * @name extract
56 | * @api public
57 | */
58 |
59 | app.task('extract', function(cb) {
60 | extract(app.options)
61 | .once('error', cb)
62 | .once('finish', cb);
63 | });
64 |
65 | /**
66 | * Default task aliased for [backup](#backup)
67 | * @name default
68 | * @api public
69 | */
70 |
71 | app.task('default', ['backup']);
72 | };
73 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./generator');
2 |
--------------------------------------------------------------------------------
/lib/backup.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var path = require('path');
5 | var tar = require('tar-fs');
6 | var mkdirp = require('mkdirp');
7 | var mm = require('micromatch');
8 | var extend = require('extend-shallow');
9 |
10 | /**
11 | * Backup the specified `.src` folder to the specified `.dest` folder using the current date to create a `.tar` file.
12 | * Additional `.ignore` option may be passed to ignore files and directories. The `.ignore` property may be anything that
13 | * is acceptable to pass to the `[micromatch][].filter` method.
14 | *
15 | * ```js
16 | * backup({src: './', dest: '/backups'});
17 | * ```
18 | * @param {Object} `options` Options to control what is archived.
19 | * @return {Stream} The stream created by [tar-fs][].
20 | * @api public
21 | */
22 |
23 | module.exports = function(options) {
24 | var opts = extend({}, options);
25 | var dest = opts.dest;
26 | if (!dest) throw new Error('expected a `dest`');
27 |
28 | var src = opts.src;
29 | if (!src) throw new Error('expected a `src`');
30 |
31 | var ignore = function() {};
32 | if (typeof opts.ignore === 'function') {
33 | ignore = opts.ignore;
34 | }
35 |
36 | if (typeof opts.ignore === 'string' || Array.isArray(opts.ignore)) {
37 | ignore = mm.filter(opts.ignore);
38 | }
39 |
40 | var fp = path.join(dest, format(new Date())) + '.tar';
41 | mkdirp.sync(dest);
42 |
43 | var output = fs.createWriteStream(fp);
44 |
45 | return tar.pack(src, {
46 | ignore: function(file) {
47 | if (path.resolve(file) === fp) {
48 | return true;
49 | }
50 | return ignore(file);
51 | }
52 | })
53 | .on('error', console.error)
54 | .pipe(output)
55 | .on('error', console.error);
56 |
57 | function format (date) {
58 | return date.getUTCFullYear() + '-' + pad(date.getUTCMonth() + 1) + '-' + pad(date.getUTCDate());
59 | }
60 |
61 | function pad (n) {
62 | return (n < 10 ? '0' : '') + n;
63 | }
64 | };
65 |
66 |
67 |
--------------------------------------------------------------------------------
/lib/extract.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var fs = require('fs');
4 | var tar = require('tar-fs');
5 | var mkdirp = require('mkdirp');
6 | var mm = require('micromatch');
7 | var extend = require('extend-shallow');
8 |
9 | /**
10 | * Extract the specified `.src` `.tar` file to the specified `.dest` folder.
11 | * Additional `.ignore` option may be passed to ignore files and directories. The `.ignore` property may be anything that
12 | * is acceptable to pass to the `[micromatch][].filter` method.
13 | *
14 | * ```js
15 | * extract({src: '/backups/2017-01-02.tar', dest: './'});
16 | * ```
17 | * @param {Object} `options` Options to control what is extracted.
18 | * @return {Stream} The stream created by [tar-fs][].
19 | * @api public
20 | */
21 |
22 | module.exports = function(options) {
23 | var opts = extend({}, options);
24 | var dest = opts.dest;
25 | if (!dest) throw new Error('expected a `dest`');
26 |
27 | var src = opts.src;
28 | if (!src) throw new Error('expected a `src`');
29 |
30 | var ignore = function() {};
31 | if (typeof opts.ignore === 'function') {
32 | ignore = opts.ignore;
33 | }
34 |
35 | if (typeof opts.ignore === 'string' || Array.isArray(opts.ignore)) {
36 | ignore = mm.filter(opts.ignore);
37 | }
38 |
39 | mkdirp.sync(dest);
40 | return fs.createReadStream(src)
41 | .on('error', console.error)
42 | .pipe(tar.extract(dest, {ignore: ignore}))
43 | .on('error', console.error);
44 | };
45 |
46 |
47 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "generate-backup",
3 | "description": "Create backup archives with generate.",
4 | "version": "0.1.0",
5 | "homepage": "https://github.com/generate/generate-backup",
6 | "author": "Brian Woodward (https://github.com/doowb)",
7 | "repository": "generate/generate-backup",
8 | "bugs": {
9 | "url": "https://github.com/generate/generate-backup/issues"
10 | },
11 | "license": "MIT",
12 | "files": [
13 | "generator.js",
14 | "index.js",
15 | "lib"
16 | ],
17 | "main": "index.js",
18 | "engines": {
19 | "node": ">=0.10.0"
20 | },
21 | "scripts": {
22 | "test": "mocha"
23 | },
24 | "dependencies": {
25 | "extend-shallow": "^2.0.1",
26 | "is-valid-app": "^0.2.1",
27 | "micromatch": "^2.3.11",
28 | "mkdirp": "^0.5.1",
29 | "tar-fs": "^1.14.0"
30 | },
31 | "devDependencies": {
32 | "delete": "^0.3.2",
33 | "generate": "^0.13.1",
34 | "gulp-format-md": "^0.1.11",
35 | "mocha": "^3.1.2",
36 | "moment": "^2.17.1",
37 | "npm-install-global": "^0.1.2"
38 | },
39 | "keywords": [
40 | "archive",
41 | "backup",
42 | "bkp",
43 | "extract",
44 | "generate",
45 | "generate-backup",
46 | "generategenerator",
47 | "generator",
48 | "tar"
49 | ],
50 | "verb": {
51 | "toc": false,
52 | "layout": "generator",
53 | "tasks": [
54 | "readme"
55 | ],
56 | "plugins": [
57 | "gulp-format-md"
58 | ],
59 | "lint": {
60 | "reflinks": true
61 | },
62 | "related": {
63 | "list": [
64 | "generate",
65 | "micromatch",
66 | "tar-fs"
67 | ]
68 | },
69 | "reflinks": [
70 | "assemble",
71 | "base",
72 | "generate",
73 | "gulp",
74 | "tar-fs",
75 | "verb",
76 | "verb-generate-readme"
77 | ]
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/test/fixtures/foo/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 |
10 | [*.md]
11 | trim_trailing_whitespace = false
12 |
--------------------------------------------------------------------------------
/test/fixtures/foo/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "ecmaFeatures": {
3 | "modules": true,
4 | "experimentalObjectRestSpread": true
5 | },
6 | "env": {
7 | "browser": false,
8 | "es6": true,
9 | "node": true,
10 | "mocha": true
11 | },
12 | "globals": {
13 | "document": false,
14 | "navigator": false,
15 | "window": false
16 | },
17 | "rules": {
18 | "accessor-pairs": 2,
19 | "arrow-spacing": [
20 | 2,
21 | {
22 | "before": true,
23 | "after": true
24 | }
25 | ],
26 | "block-spacing": [
27 | 2,
28 | "always"
29 | ],
30 | "brace-style": [
31 | 2,
32 | "1tbs",
33 | {
34 | "allowSingleLine": true
35 | }
36 | ],
37 | "comma-dangle": [
38 | 2,
39 | "never"
40 | ],
41 | "comma-spacing": [
42 | 2,
43 | {
44 | "before": false,
45 | "after": true
46 | }
47 | ],
48 | "comma-style": [
49 | 2,
50 | "last"
51 | ],
52 | "constructor-super": 2,
53 | "curly": [
54 | 2,
55 | "multi-line"
56 | ],
57 | "dot-location": [
58 | 2,
59 | "property"
60 | ],
61 | "eol-last": 2,
62 | "eqeqeq": [
63 | 2,
64 | "allow-null"
65 | ],
66 | "generator-star-spacing": [
67 | 2,
68 | {
69 | "before": true,
70 | "after": true
71 | }
72 | ],
73 | "handle-callback-err": [
74 | 2,
75 | "^(err|error)$"
76 | ],
77 | "indent": [
78 | 2,
79 | 2,
80 | {
81 | "SwitchCase": 1
82 | }
83 | ],
84 | "key-spacing": [
85 | 2,
86 | {
87 | "beforeColon": false,
88 | "afterColon": true
89 | }
90 | ],
91 | "keyword-spacing": [
92 | 2,
93 | {
94 | "before": true,
95 | "after": true
96 | }
97 | ],
98 | "new-cap": [
99 | 2,
100 | {
101 | "newIsCap": true,
102 | "capIsNew": false
103 | }
104 | ],
105 | "new-parens": 2,
106 | "no-array-constructor": 2,
107 | "no-caller": 2,
108 | "no-class-assign": 2,
109 | "no-cond-assign": 2,
110 | "no-const-assign": 2,
111 | "no-control-regex": 2,
112 | "no-debugger": 2,
113 | "no-delete-var": 2,
114 | "no-dupe-args": 2,
115 | "no-dupe-class-members": 2,
116 | "no-dupe-keys": 2,
117 | "no-duplicate-case": 2,
118 | "no-empty-character-class": 2,
119 | "no-eval": 2,
120 | "no-ex-assign": 2,
121 | "no-extend-native": 2,
122 | "no-extra-bind": 2,
123 | "no-extra-boolean-cast": 2,
124 | "no-extra-parens": [
125 | 2,
126 | "functions"
127 | ],
128 | "no-fallthrough": 2,
129 | "no-floating-decimal": 2,
130 | "no-func-assign": 2,
131 | "no-implied-eval": 2,
132 | "no-inner-declarations": [
133 | 2,
134 | "functions"
135 | ],
136 | "no-invalid-regexp": 2,
137 | "no-irregular-whitespace": 2,
138 | "no-iterator": 2,
139 | "no-label-var": 2,
140 | "no-labels": 2,
141 | "no-lone-blocks": 2,
142 | "no-mixed-spaces-and-tabs": 2,
143 | "no-multi-spaces": 2,
144 | "no-multi-str": 2,
145 | "no-multiple-empty-lines": [
146 | 2,
147 | {
148 | "max": 1
149 | }
150 | ],
151 | "no-native-reassign": 0,
152 | "no-negated-in-lhs": 2,
153 | "no-new": 2,
154 | "no-new-func": 2,
155 | "no-new-object": 2,
156 | "no-new-require": 2,
157 | "no-new-wrappers": 2,
158 | "no-obj-calls": 2,
159 | "no-octal": 2,
160 | "no-octal-escape": 2,
161 | "no-proto": 0,
162 | "no-redeclare": 2,
163 | "no-regex-spaces": 2,
164 | "no-return-assign": 2,
165 | "no-self-compare": 2,
166 | "no-sequences": 2,
167 | "no-shadow-restricted-names": 2,
168 | "no-spaced-func": 2,
169 | "no-sparse-arrays": 2,
170 | "no-this-before-super": 2,
171 | "no-throw-literal": 2,
172 | "no-trailing-spaces": 0,
173 | "no-undef": 2,
174 | "no-undef-init": 2,
175 | "no-unexpected-multiline": 2,
176 | "no-unneeded-ternary": [
177 | 2,
178 | {
179 | "defaultAssignment": false
180 | }
181 | ],
182 | "no-unreachable": 2,
183 | "no-unused-vars": [
184 | 2,
185 | {
186 | "vars": "all",
187 | "args": "none"
188 | }
189 | ],
190 | "no-useless-call": 0,
191 | "no-with": 2,
192 | "one-var": [
193 | 0,
194 | {
195 | "initialized": "never"
196 | }
197 | ],
198 | "operator-linebreak": [
199 | 0,
200 | "after",
201 | {
202 | "overrides": {
203 | "?": "before",
204 | ":": "before"
205 | }
206 | }
207 | ],
208 | "padded-blocks": [
209 | 0,
210 | "never"
211 | ],
212 | "quotes": [
213 | 2,
214 | "single",
215 | "avoid-escape"
216 | ],
217 | "radix": 2,
218 | "semi": [
219 | 2,
220 | "always"
221 | ],
222 | "semi-spacing": [
223 | 2,
224 | {
225 | "before": false,
226 | "after": true
227 | }
228 | ],
229 | "space-before-blocks": [
230 | 2,
231 | "always"
232 | ],
233 | "space-before-function-paren": [
234 | 2,
235 | "never"
236 | ],
237 | "space-in-parens": [
238 | 2,
239 | "never"
240 | ],
241 | "space-infix-ops": 2,
242 | "space-unary-ops": [
243 | 2,
244 | {
245 | "words": true,
246 | "nonwords": false
247 | }
248 | ],
249 | "spaced-comment": [
250 | 0,
251 | "always",
252 | {
253 | "markers": [
254 | "global",
255 | "globals",
256 | "eslint",
257 | "eslint-disable",
258 | "*package",
259 | "!",
260 | ","
261 | ]
262 | }
263 | ],
264 | "use-isnan": 2,
265 | "valid-typeof": 2,
266 | "wrap-iife": [
267 | 2,
268 | "any"
269 | ],
270 | "yoda": [
271 | 2,
272 | "never"
273 | ]
274 | }
275 | }
276 |
--------------------------------------------------------------------------------
/test/fixtures/foo/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/test/fixtures/foo/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | coverage
--------------------------------------------------------------------------------
/test/fixtures/foo/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - 'node'
5 | - '6'
6 |
--------------------------------------------------------------------------------
/test/fixtures/foo/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Brian Woodward
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/test/fixtures/foo/README.md:
--------------------------------------------------------------------------------
1 | # foo [](https://npmjs.org/package/foo) [](https://travis-ci.org/doowb/foo)
2 |
3 | > test project
4 |
5 | ## Installation
6 |
7 | ```sh
8 | $ npm install --save foo
9 | ```
10 |
11 | ## Usage
12 |
13 | ```js
14 | var foo = require('foo');
15 | foo();
16 | ```
17 |
18 | ## License
19 |
20 | MIT © [Brian Woodward](https://github.com/doowb)
21 |
--------------------------------------------------------------------------------
/test/fixtures/foo/contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing to foo
2 |
3 | First and foremost, thank you! We appreciate that you want to contribute to foo, your time is valuable, and your contributions mean a lot to us.
4 |
5 | **What does "contributing" mean?**
6 |
7 | Creating an issue is the simplest form of contributing to a project. But there are many ways to contribute, including the following:
8 |
9 | - Updating or correcting documentation
10 | - Feature requests
11 | - Bug reports
12 |
13 | If you'd like to learn more about contributing in general, the [Guide to Idiomatic Contributing](https://github.com/jonschlinkert/idiomatic-contributing) has a lot of useful information.
14 |
15 | **Showing support for foo**
16 |
17 | Please keep in mind that open source software is built by people like you, who spend their free time creating things the rest the community can use.
18 |
19 | Don't have time to contribute? No worries, here are some other ways to show your support for foo:
20 |
21 | - star the [project](https://github.com/doowb/foo)
22 | - tweet your support for foo
23 |
24 | ## Issues
25 |
26 | ### Before creating an issue
27 |
28 | Please try to determine if the issue is caused by an underlying library, and if so, create the issue there. Sometimes this is difficult to know. We only ask that you attempt to give a reasonable attempt to find out. Oftentimes the readme will have advice about where to go to create issues.
29 |
30 | Try to follow these guidelines
31 |
32 | - **Investigate the issue**:
33 | - **Check the readme** - oftentimes you will find notes about creating issues, and where to go depending on the type of issue.
34 | - Create the issue in the appropriate repository.
35 |
36 | ### Creating an issue
37 |
38 | Please be as descriptive as possible when creating an issue. Give us the information we need to successfully answer your question or address your issue by answering the following in your issue:
39 |
40 | - **version**: please note the version of foo are you using
41 | - **extensions, plugins, helpers, etc** (if applicable): please list any extensions you're using
42 | - **error messages**: please paste any error messages into the issue, or a [gist](https://gist.github.com/)
43 |
44 | ## Above and beyond
45 |
46 | Here are some tips for creating idiomatic issues. Taking just a little bit extra time will make your issue easier to read, easier to resolve, more likely to be found by others who have the same or similar issue in the future.
47 |
48 | - read the [Guide to Idiomatic Contributing](https://github.com/jonschlinkert/idiomatic-contributing)
49 | - take some time to learn basic markdown. This [markdown cheatsheet](https://gist.github.com/jonschlinkert/5854601) is super helpful, as is the GitHub guide to [basic markdown](https://help.github.com/articles/markdown-basics/).
50 | - Learn about [GitHub Flavored Markdown](https://help.github.com/articles/github-flavored-markdown/). And if you want to really go above and beyond, read [mastering markdown](https://guides.github.com/features/mastering-markdown/).
51 | - use backticks to wrap code. This ensures that code will retain its format, making it much more readable to others
52 | - use syntax highlighting by adding the correct language name after the first "code fence"
53 |
54 |
55 | [node-glob]: https://github.com/isaacs/node-glob
56 | [micromatch]: https://github.com/jonschlinkert/micromatch
57 | [so]: http://stackoverflow.com/questions/tagged/foo
--------------------------------------------------------------------------------
/test/fixtures/foo/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function() {
4 | };
5 |
--------------------------------------------------------------------------------
/test/fixtures/foo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "foo",
3 | "description": "test project",
4 | "version": "0.1.0",
5 | "homepage": "https://github.com/doowb/foo",
6 | "author": "Brian Woodward (https://github.com/doowb)",
7 | "repository": "doowb/foo",
8 | "bugs": {
9 | "url": "https://github.com/doowb/foo/issues"
10 | },
11 | "license": "MIT",
12 | "files": [
13 | "index.js",
14 | "LICENSE"
15 | ],
16 | "main": "index.js",
17 | "engines": {
18 | "node": ">=0.10.0"
19 | },
20 | "scripts": {
21 | "test": "mocha"
22 | },
23 | "keywords": [
24 | "generategenerator"
25 | ],
26 | "dependencies": {
27 | "node-bar": "^0.2.0",
28 | "node-foo": "^0.2.3"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/test/plugin.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('mocha');
4 | var assert = require('assert');
5 | var generate = require('generate');
6 | var generator = require('../');
7 | var app;
8 |
9 | describe('generate-backup', function() {
10 | beforeEach(function() {
11 | app = generate();
12 | });
13 |
14 | describe('plugin', function() {
15 | it('should add tasks to the instance', function() {
16 | app.use(generator);
17 | assert(app.tasks.hasOwnProperty('default'));
18 | assert(app.tasks.hasOwnProperty('backup'));
19 | });
20 |
21 | it('should only register the plugin once', function(cb) {
22 | var count = 0;
23 | app.on('plugin', function(name) {
24 | if (name === 'generate-backup') {
25 | count++;
26 | }
27 | });
28 | app.use(generator);
29 | app.use(generator);
30 | app.use(generator);
31 | assert.equal(count, 1);
32 | cb();
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | require('mocha');
4 | var fs = require('fs');
5 | var path = require('path');
6 | var assert = require('assert');
7 | var moment = require('moment');
8 | var generate = require('generate');
9 | var npm = require('npm-install-global');
10 | var del = require('delete');
11 | var pkg = require('../package');
12 | var generator = require('..');
13 | var app;
14 |
15 | var today = moment.utc().format('YYYY-MM-DD');
16 | var isTravis = process.env.CI || process.env.TRAVIS;
17 | var fixtures = path.resolve.bind(path, __dirname, 'fixtures');
18 | var actual = path.resolve.bind(path, __dirname, 'actual');
19 |
20 | function exists(name, cb) {
21 | return function(err) {
22 | if (err) return cb(err);
23 | var filepath = actual(name);
24 |
25 | fs.stat(filepath, function(err, stat) {
26 | if (err) return cb(err);
27 | assert(stat);
28 | del(actual(), cb);
29 | });
30 | };
31 | }
32 |
33 | describe('generate-backup', function() {
34 | this.timeout(5000);
35 | this.slow(250);
36 |
37 | if (!process.env.CI && !process.env.TRAVIS) {
38 | before(function(cb) {
39 | npm.maybeInstall('generate', cb);
40 | });
41 | }
42 |
43 | beforeEach(function(cb) {
44 | app = generate({silent: true});
45 | app.cwd = fixtures();
46 | app.option('dest', actual());
47 | app.option('src', fixtures());
48 |
49 | // see: https://github.com/jonschlinkert/ask-when
50 | app.option('askWhen', 'not-answered');
51 |
52 | // set default data to use in templates. feel free to remove anything
53 | // that isn't used (e.g. if "username" isn't defined in templates, just remove it)
54 | app.data(pkg);
55 | app.data('project', pkg);
56 | app.data('username', 'foo');
57 | app.data('owner', 'foo');
58 | del(actual(), cb);
59 | });
60 |
61 | afterEach(function(cb) {
62 | del(actual(), cb);
63 | });
64 |
65 | describe('tasks', function() {
66 | it('should extend tasks onto the instance', function() {
67 | app.use(generator);
68 | assert(app.tasks.hasOwnProperty('default'));
69 | assert(app.tasks.hasOwnProperty('backup'));
70 | });
71 |
72 | it('should run the `default` task with .build', function(cb) {
73 | this.timeout(30000);
74 | app.use(generator);
75 | app.build('default', exists(`${today}.tar`, cb));
76 | });
77 |
78 | it('should run the `default` task with .generate', function(cb) {
79 | app.use(generator);
80 | app.generate('default', exists(`${today}.tar`, cb));
81 | });
82 | });
83 |
84 | describe('backup (CLI)', function() {
85 | it('should run the default task using the `generate-backup` name', function(cb) {
86 | if (isTravis) {
87 | this.skip();
88 | return;
89 | }
90 | app.use(generator);
91 | app.generate('generate-backup', exists(`${today}.tar`, cb));
92 | });
93 |
94 | it('should run the default task using the `generator` generator alias', function(cb) {
95 | if (isTravis) {
96 | this.skip();
97 | return;
98 | }
99 | app.use(generator);
100 | app.generate('backup', exists(`${today}.tar`, cb));
101 | });
102 | });
103 |
104 | describe('backup (API)', function() {
105 | it('should run the default task on the generator', function(cb) {
106 | app.register('backup', generator);
107 | app.generate('backup', exists(`${today}.tar`, cb));
108 | });
109 |
110 | it('should run the `backup` task', function(cb) {
111 | app.register('backup', generator);
112 | app.generate('backup:backup', exists(`${today}.tar`, cb));
113 | });
114 |
115 | it('should run the `default` task when defined explicitly', function(cb) {
116 | app.register('backup', generator);
117 | app.generate('backup:default', exists(`${today}.tar`, cb));
118 | });
119 | });
120 |
121 | describe('sub-generator', function() {
122 | it('should work as a sub-generator', function(cb) {
123 | app.register('foo', function(foo) {
124 | foo.register('backup', generator);
125 | });
126 | app.generate('foo.backup', exists(`${today}.tar`, cb));
127 | });
128 |
129 | it('should run the `default` task by default', function(cb) {
130 | app.register('foo', function(foo) {
131 | foo.register('backup', generator);
132 | });
133 | app.generate('foo.backup', exists(`${today}.tar`, cb));
134 | });
135 |
136 | it('should run the `generator:default` task when defined explicitly', function(cb) {
137 | app.register('foo', function(foo) {
138 | foo.register('backup', generator);
139 | });
140 | app.generate('foo.backup:default', exists(`${today}.tar`, cb));
141 | });
142 |
143 | it('should run the `generator:backup` task', function(cb) {
144 | app.register('foo', function(foo) {
145 | foo.register('backup', generator);
146 | });
147 | app.generate('foo.backup:backup', exists(`${today}.tar`, cb));
148 | });
149 |
150 | it('should work with nested sub-generators', function(cb) {
151 | app
152 | .register('foo', generator)
153 | .register('bar', generator)
154 | .register('baz', generator)
155 |
156 | app.generate('foo.bar.baz', exists(`${today}.tar`, cb));
157 | });
158 | });
159 | });
160 |
--------------------------------------------------------------------------------