master_delivery 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bd9ff051619b6dac6107d7668710401371bdf30c1de87d8e9ab276a5068f60ad
4
+ data.tar.gz: d8fd9a7aeea81fc837894991f8f174d1fb9bfd178fab84a0a7dd4fe4a5ba3093
5
+ SHA512:
6
+ metadata.gz: 870094f61f466eb9537b7981409c473214d79a952b8fee335ca4f29eeecee458bbeba261396ce082c4604c2aeb660e53f3f3fa2670e39b9cab7e5520aea029f2
7
+ data.tar.gz: 7f9db3fbd3e9df232868fc1c9c65bf2436a98a0fcda152071e03f7eefb69c72e3795b590109ed9f94e26fe476bfa2428349830b920f39d7334cc2d476eb2093e
@@ -0,0 +1,10 @@
1
+ **/.DS_Store
2
+ .rspec_status
3
+ /.bundle/
4
+ /.yardoc
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,57 @@
1
+ # ** Default values of all configuration are written in**
2
+ # https://github.com/rubocop-hq/rubocop/blob/master/config/default.yml
3
+ #
4
+ # Detail examples of each configuration are
5
+ # https://rubocop.readthedocs.io/en/latest/cops_layout
6
+ #
7
+ # General guide-line is
8
+ # https://github.com/rubocop-hq/ruby-style-guide
9
+
10
+ require:
11
+ - rubocop-performance
12
+ - rubocop-rspec
13
+
14
+ AllCops:
15
+ TargetRubyVersion: 2.5
16
+
17
+ Layout/EndAlignment:
18
+ Enabled: true
19
+ AutoCorrect: true
20
+
21
+ Layout/LineLength:
22
+ Enabled: true
23
+ AutoCorrect: false
24
+ Max: 120
25
+
26
+ Layout/SpaceAroundMethodCallOperator:
27
+ Enabled: true
28
+
29
+ Lint/RaiseException:
30
+ Enabled: true
31
+
32
+ Lint/StructNewOverride:
33
+ Enabled: true
34
+
35
+ Metrics/BlockLength:
36
+ Enabled: true
37
+ Max: 30
38
+ ExcludedMethods: ['describe', 'context']
39
+
40
+ Metrics/MethodLength:
41
+ Enabled: true
42
+ Max: 30
43
+
44
+ Style/ExponentialNotation:
45
+ Enabled: true
46
+
47
+ Style/HashEachMethods:
48
+ Enabled: true
49
+ AutoCorrect: true
50
+
51
+ Style/HashTransformKeys:
52
+ Enabled: true
53
+ AutoCorrect: true
54
+
55
+ Style/HashTransformValues:
56
+ Enabled: true
57
+ AutoCorrect: true
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 2.7.1
6
+ before_install: gem install bundler -v 2.1.4
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ ## [v1.0.1](https://github.com/shinyaohtani/master_delivery/tree/v1.0.1) (2020-04-25)
4
+
5
+ [Full Changelog](https://github.com/shinyaohtani/master_delivery/compare/4b0351ffd3cc1c8ddfeb76d39e2bddd0b8baa5a8...v1.0.1)
6
+
7
+ **Closed issues:**
8
+
9
+ - v1.0.1 release [\#1](https://github.com/shinyaohtani/master_delivery/issues/1)
10
+
11
+ **Merged pull requests:**
12
+
13
+ - v1.0.1 release [\#2](https://github.com/shinyaohtani/master_delivery/pull/2) ([shinyaohtani](https://github.com/shinyaohtani))
14
+
15
+
16
+
17
+ \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)*
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at @shinyaohtani. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [https://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: https://contributor-covenant.org
74
+ [version]: https://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in master_delivery.gemspec
6
+ gemspec
@@ -0,0 +1,138 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ master_delivery (1.0.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activesupport (6.0.2.2)
10
+ concurrent-ruby (~> 1.0, >= 1.0.2)
11
+ i18n (>= 0.7, < 2)
12
+ minitest (~> 5.1)
13
+ tzinfo (~> 1.1)
14
+ zeitwerk (~> 2.2)
15
+ addressable (2.7.0)
16
+ public_suffix (>= 2.0.2, < 5.0)
17
+ ast (2.4.0)
18
+ async (1.24.2)
19
+ console (~> 1.0)
20
+ nio4r (~> 2.3)
21
+ timers (~> 4.1)
22
+ async-http (0.51.2)
23
+ async (~> 1.23)
24
+ async-io (~> 1.28)
25
+ async-pool (~> 0.2)
26
+ protocol-http (~> 0.18.0)
27
+ protocol-http1 (~> 0.12.0)
28
+ protocol-http2 (~> 0.13.0)
29
+ async-http-faraday (0.9.0)
30
+ async-http (~> 0.42)
31
+ faraday
32
+ async-io (1.28.0)
33
+ async (~> 1.14)
34
+ async-pool (0.2.0)
35
+ async (~> 1.8)
36
+ byebug (11.1.3)
37
+ coderay (1.1.2)
38
+ concurrent-ruby (1.1.6)
39
+ console (1.8.2)
40
+ diff-lcs (1.3)
41
+ faraday (1.0.1)
42
+ multipart-post (>= 1.2, < 3)
43
+ faraday-http-cache (2.2.0)
44
+ faraday (>= 0.8)
45
+ github_changelog_generator (1.15.2)
46
+ activesupport
47
+ async-http-faraday
48
+ faraday-http-cache
49
+ multi_json
50
+ octokit (~> 4.6)
51
+ rainbow (>= 2.2.1)
52
+ rake (>= 10.0)
53
+ retriable (~> 3.0)
54
+ i18n (1.8.2)
55
+ concurrent-ruby (~> 1.0)
56
+ jaro_winkler (1.5.4)
57
+ method_source (1.0.0)
58
+ minitest (5.14.0)
59
+ multi_json (1.14.1)
60
+ multipart-post (2.1.1)
61
+ nio4r (2.5.2)
62
+ octokit (4.18.0)
63
+ faraday (>= 0.9)
64
+ sawyer (~> 0.8.0, >= 0.5.3)
65
+ parallel (1.19.1)
66
+ parser (2.7.1.1)
67
+ ast (~> 2.4.0)
68
+ protocol-hpack (1.4.2)
69
+ protocol-http (0.18.0)
70
+ protocol-http1 (0.12.0)
71
+ protocol-http (~> 0.18)
72
+ protocol-http2 (0.13.3)
73
+ protocol-hpack (~> 1.4)
74
+ protocol-http (~> 0.18)
75
+ pry (0.13.1)
76
+ coderay (~> 1.1)
77
+ method_source (~> 1.0)
78
+ pry-byebug (3.9.0)
79
+ byebug (~> 11.0)
80
+ pry (~> 0.13.0)
81
+ public_suffix (4.0.4)
82
+ rainbow (3.0.0)
83
+ rake (13.0.1)
84
+ retriable (3.1.2)
85
+ rexml (3.2.4)
86
+ rspec (3.9.0)
87
+ rspec-core (~> 3.9.0)
88
+ rspec-expectations (~> 3.9.0)
89
+ rspec-mocks (~> 3.9.0)
90
+ rspec-core (3.9.1)
91
+ rspec-support (~> 3.9.1)
92
+ rspec-expectations (3.9.1)
93
+ diff-lcs (>= 1.2.0, < 2.0)
94
+ rspec-support (~> 3.9.0)
95
+ rspec-mocks (3.9.1)
96
+ diff-lcs (>= 1.2.0, < 2.0)
97
+ rspec-support (~> 3.9.0)
98
+ rspec-support (3.9.2)
99
+ rubocop (0.82.0)
100
+ jaro_winkler (~> 1.5.1)
101
+ parallel (~> 1.10)
102
+ parser (>= 2.7.0.1)
103
+ rainbow (>= 2.2.2, < 4.0)
104
+ rexml
105
+ ruby-progressbar (~> 1.7)
106
+ unicode-display_width (>= 1.4.0, < 2.0)
107
+ rubocop-performance (1.5.2)
108
+ rubocop (>= 0.71.0)
109
+ rubocop-rspec (1.38.1)
110
+ rubocop (>= 0.68.1)
111
+ ruby-progressbar (1.10.1)
112
+ sawyer (0.8.2)
113
+ addressable (>= 2.3.5)
114
+ faraday (> 0.8, < 2.0)
115
+ thread_safe (0.3.6)
116
+ timers (4.3.0)
117
+ tzinfo (1.2.7)
118
+ thread_safe (~> 0.1)
119
+ unicode-display_width (1.7.0)
120
+ zeitwerk (2.3.0)
121
+
122
+ PLATFORMS
123
+ ruby
124
+
125
+ DEPENDENCIES
126
+ bundler (~> 2.0)
127
+ github_changelog_generator (>= 1.15.0)
128
+ master_delivery!
129
+ pry (>= 0.12.2)
130
+ pry-byebug (>= 3.9.0)
131
+ rake (>= 12.3.3)
132
+ rspec (>= 3.9.0)
133
+ rubocop (>= 0.80.1)
134
+ rubocop-performance (>= 1.5.2)
135
+ rubocop-rspec (>= 1.38.1)
136
+
137
+ BUNDLED WITH
138
+ 2.1.4
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Shinya Ohtani
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
13
+ all 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
21
+ THE SOFTWARE.
@@ -0,0 +1,87 @@
1
+ # MasterDelivery
2
+
3
+ `MasterDelivery` is a master file manager utility. `MasterDelivery` delivers all master files managed in a single master snapshot directory into the specified directory while maintaining the hierarchy of the master snapshot directory. If the destination file already exists, back it up first and then deliver the master file.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'master_delivery'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install master_delivery
20
+
21
+ ## Usage
22
+
23
+ ```
24
+ Example:
25
+ If you specify MASTER_DIR and DELIVERY_ROOT as follows:
26
+ MASTER_DIR: -m ~/masters/my_home_setting
27
+ DELIVERY_ROOT: -d /Users/foo
28
+
29
+ and suppose master files in MASTER_DIR are as follows:
30
+ ~/master/my_home_setting/.zshrc
31
+ ~/master/my_home_setting/work/.rubocop.yml
32
+
33
+ then these files will be delivered as the following files:
34
+ /Users/foo/.zshrc
35
+ /Users/foo/work/.rubocop.yml
36
+
37
+ Usage: master_delivery -m <dir> -d <dir> [options]
38
+ Required:
39
+ -m, --master [MASTER_DIR] Master snapshot directory. All master files in this
40
+ directory will be placed in the "delivery root",
41
+ maintaining the directory structure.
42
+ Only regular files will be delivered. That is,
43
+ all symbolic link files and empty directories in
44
+ MASTER_DIR are ignored.
45
+ -d, --delivery [DELIVERY_ROOT] Delivery root, or destination directory. All master
46
+ files will be placed in this while maintaining the master
47
+ directory structure.
48
+
49
+ Optional:
50
+ -t, --type [DELIVERY_TYPE] Delivery type. "symbolic_link" or "regular_file" is accepted.
51
+ Master files will be delivered as symbolic links (ln -s)
52
+ or regular files (cp).
53
+ (default: symbolic_link)
54
+ -b, --backup [BACKUP_ROOT] Backup root, or Evacuation destination directory.
55
+ All current active files will be moved into this
56
+ directory maintaining the directory structure.
57
+ Backup root will be created automatically. (mkdir -p)
58
+ (defualt: MASTER_DIR/../backup)
59
+ -D, --[no-]dryrun Instead of actually moving or copying files, display
60
+ the commands on stderr.
61
+ We strongly recommend "--dryrun" before running.
62
+ (default: --no-dryrun)
63
+
64
+ Common options:
65
+ -h, --help Show this message
66
+ -V, --version Show version
67
+
68
+ ```
69
+
70
+ ## Development
71
+
72
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
73
+
74
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
75
+
76
+ ## Contributing
77
+
78
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/master_delivery. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/master_delivery/blob/master/CODE_OF_CONDUCT.md).
79
+
80
+
81
+ ## License
82
+
83
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
84
+
85
+ ## Code of Conduct
86
+
87
+ Everyone interacting in the MasterDelivery project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/master_delivery/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
9
+
10
+ require 'github_changelog_generator/task'
11
+ GitHubChangelogGenerator::RakeTask.new :changelog do |config|
12
+ config.base = 'CHANGELOG.md'
13
+ config.future_release = "v#{MasterDelivery::VERSION}"
14
+ config.project = 'master_delivery'
15
+ config.user = 'shinyaohtani'
16
+ config.verbose = false
17
+
18
+ # other changelog options (values are default)
19
+ #
20
+ # -- labels
21
+ #:config.breaking_labels = ["backwards-incompatible", "Backwards incompatible", "breaking"]
22
+ #:config.bug_labels = ["bug", "Bug", "Type: Bug"]
23
+ #:config.deprecated_labels = ["deprecated", "Deprecated", "Type: Deprecated"]
24
+ #:config.enhancement_labels = ["enhancement", "Enhancement", "Type: Enhancement"]
25
+ #:config.exclude_labels = ['duplicate', 'question', 'invalid', 'wontfix',
26
+ #: 'Duplicate', 'Question', 'Invalid', 'Wontfix',
27
+ #: 'Meta: Exclude From Changelog']
28
+ #:config.removed_labels = ["removed", "Removed", "Type: Removed"]
29
+ #:config.security_labels = ["security", "Security", "Type: Security"]
30
+ #:config.summary_labels = ["Release summary", "release-summary", "Summary", "summary"]
31
+ # -- prefix
32
+ #:config.breaking_prefix = "**Breaking changes:**"
33
+ #:config.bug_prefix = "**Fixed bugs:**"
34
+ #:config.deprecated_prefix = "**Deprecated:**"
35
+ #:config.enhancement_prefix = "**Implemented enhancements:**"
36
+ #:config.header = "# Changelog"
37
+ #:config.issue_prefix = "**Closed issues:**"
38
+ #:config.merge_prefix = "**Merged pull requests:**"
39
+ #:config.removed_prefix = "**Removed:**"
40
+ #:config.security_prefix = "**Security fixes:**"
41
+ #:config.summary_prefix = ""
42
+ # -- others
43
+ #:config.add_issues_wo_labels = true
44
+ #:config.add_pr_wo_labels = true
45
+ #:config.add_sections = {}
46
+ #:config.author = true
47
+ #:config.compare_link = true
48
+ #:config.configure_sections = {}
49
+ #:config.date_format = "%Y-%m-%d"
50
+ #:config.filter_issues_by_milestone = true
51
+ #:config.http_cache = true
52
+ #:config.issue_line_labels = []
53
+ #:config.issues = true
54
+ #:config.max_issues = nil
55
+ #:config.output = "CHANGELOG.md"
56
+ #:config.pulls = true
57
+ #:config.require = []
58
+ #:config.simple_list = false
59
+ #:config.ssl_ca_file = nil
60
+ #:config.unreleased = true
61
+ #:config.unreleased_label = "Unreleased"
62
+ end
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'master_delivery'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'cli_master_delivery'
5
+
6
+ cli_md = MasterDelivery::CliMasterDelivery.new
7
+ cli_md.parse_options
8
+ cli_md.run
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # converter module from path to url
5
+ module MasterDelivery
6
+ require 'master_delivery'
7
+ require 'optparse'
8
+
9
+ DESC_MASTER_DIR = <<~MASTER
10
+ Master snapshot directory. All master files in this
11
+ directory will be placed in the "delivery root",
12
+ maintaining the directory structure.
13
+ Only regular files will be delivered. That is,
14
+ all symbolic link files and empty directories in
15
+ MASTER_DIR are ignored.
16
+ MASTER
17
+ DESC_DELIVERY_ROOT = <<~DELIVERY
18
+ Delivery root, or destination directory. All master
19
+ files will be placed in this while maintaining the master
20
+ directory structure.
21
+ DELIVERY
22
+ DESC_BACKUP_ROOT = <<~BACKUP
23
+ Backup root, or Evacuation destination directory.
24
+ All current active files will be moved into this
25
+ directory maintaining the directory structure.
26
+ Backup root will be created automatically. (mkdir -p)
27
+ (defualt: MASTER_DIR/../backup)
28
+ BACKUP
29
+ VALUE_DELIVERY_TYPE = %w[symbolic_link regular_file].freeze
30
+ DESC_DELIVERY_TYPE = <<~TYPE
31
+ Delivery type. "#{VALUE_DELIVERY_TYPE.join('" or "')}" is accepted.
32
+ Master files will be delivered as symbolic links (ln -s)
33
+ or regular files (cp).
34
+ (default: #{VALUE_DELIVERY_TYPE[0]})
35
+ TYPE
36
+ DESC_DRYRUN = <<~DRYRUN
37
+ Instead of actually moving or copying files, display
38
+ the commands on stderr.
39
+ We strongly recommend "--dryrun" before running.
40
+ (default: --no-dryrun)
41
+ DRYRUN
42
+ DESC_EXAMPLE = <<~EXAMPLE
43
+ Example:
44
+ If you specify MASTER_DIR and DELIVERY_ROOT as follows:
45
+ MASTER_DIR: -m ~/masters/my_home_setting
46
+ DELIVERY_ROOT: -d /Users/foo
47
+
48
+ and suppose master files in MASTER_DIR are as follows:
49
+ ~/master/my_home_setting/.zshrc
50
+ ~/master/my_home_setting/work/.rubocop.yml
51
+
52
+ then these files will be delivered as the following files:
53
+ /Users/foo/.zshrc
54
+ /Users/foo/work/.rubocop.yml
55
+ EXAMPLE
56
+
57
+ # command line wrapper
58
+ class CliMasterDelivery # rubocop:disable Metrics/ClassLength
59
+ attr_accessor :params
60
+
61
+ def initialize
62
+ @params = { type: VALUE_DELIVERY_TYPE[0].to_sym, dryrun: false }
63
+ end
64
+
65
+ def parse_options
66
+ OptionParser.new do |opts|
67
+ opts = define_options(opts)
68
+ opts.parse!(ARGV, into: @params)
69
+ end
70
+ end
71
+
72
+ def run
73
+ unless check_param_consistency
74
+ puts 'See more with --help option'
75
+ return
76
+ end
77
+ master_dir = File.expand_path(@params[:master])
78
+ master_id = File.basename(master_dir)
79
+ md = MasterDelivery.new(File.dirname(master_dir), @params[:backup])
80
+ arg_set = [master_id, @params[:delivery]]
81
+ arg_hash = { type: @params[:type], dryrun: @params[:dryrun] }
82
+ return unless md.confirm(*arg_set, **arg_hash)
83
+
84
+ md.deliver(*arg_set, **arg_hash)
85
+ puts 'done!'
86
+ end
87
+
88
+ private
89
+
90
+ def define_options(opts) # rubocop:disable Metrics/AbcSize
91
+ opts.version = VERSION
92
+ opts.separator ' Required:'
93
+ opts.on('-m [MASTER_DIR]', '--master [MASTER_DIR]', *DESC_MASTER_DIR.split(/\R/)) { |v| v }
94
+ opts.on('-d [DELIVERY_ROOT]', '--delivery [DELIVERY_ROOT]', *DESC_DELIVERY_ROOT.split(/\R/)) { |v| v }
95
+ opts.separator ''
96
+ opts.separator ' Optional:'
97
+ opts.on('-t [DELIVERY_TYPE]', '--type [DELIVERY_TYPE]', *DESC_DELIVERY_TYPE.split(/\R/), &:to_sym)
98
+ opts.on('-b [BACKUP_ROOT]', '--backup [BACKUP_ROOT]', *DESC_BACKUP_ROOT.split(/\R/)) { |v| v }
99
+ opts.on('-D', '--[no-]dryrun', *DESC_DRYRUN.split(/\R/)) { |v| v }
100
+ opts.separator ''
101
+ opts.separator ' Common options:'
102
+ # opts.on('-v', '--verbose', 'Verbose mode. default: no') { |v| v }
103
+ opts.on_tail('-h', '--help', 'Show this message') do
104
+ puts opts
105
+ exit
106
+ end
107
+ opts.on_tail('-V', '--version', 'Show version') do
108
+ puts opts.ver
109
+ exit
110
+ end
111
+ opts.banner = <<~BANNER
112
+
113
+ #{opts.ver}
114
+ #{DESCRIPTION}
115
+ #{DESC_EXAMPLE}
116
+ Usage: #{opts.program_name} -m <dir> -d <dir> [options]
117
+ BANNER
118
+ opts
119
+ end
120
+
121
+ def check_param_consistency
122
+ check_param_master &&
123
+ check_param_delivery &&
124
+ check_param_backup &&
125
+ check_param_type &&
126
+ check_param_argv
127
+ end
128
+
129
+ def check_param_master
130
+ if @params[:master].nil?
131
+ puts "Specify master snapshot directory by option '-m'"
132
+ elsif !File.directory?(@params[:master])
133
+ puts "Invalid master snapshot directory: #{@params[:master]}"
134
+ else
135
+ return true
136
+ end
137
+ false
138
+ end
139
+
140
+ def check_param_delivery
141
+ if @params[:delivery].nil?
142
+ puts "Specify delivery root by option '-d'"
143
+ return false
144
+ end
145
+ master_dir = File.expand_path(@params[:master])
146
+ delivery_root = File.expand_path(@params[:delivery])
147
+ if delivery_root.start_with?(master_dir)
148
+ puts <<~INCLUSION
149
+ Invalid dirs. MASTER_DIR must not include DELIVERY_ROOT.
150
+ MASTER_DIR: #{master_dir}
151
+ DELIVERY_ROOT: #{delivery_root}
152
+ INCLUSION
153
+ return false
154
+ end
155
+ true
156
+ end
157
+
158
+ def check_param_backup
159
+ master_dir = File.expand_path(@params[:master])
160
+ bkp = @params[:backup]
161
+ if !bkp.nil? && !bkp.empty?
162
+ backup_root = File.expand_path(bkp)
163
+ if backup_root.start_with?(master_dir)
164
+ puts <<~INCLUSION
165
+ Invalid dirs. MASTER_DIR must not include BACKUP_ROOT.
166
+ MASTER_DIR: #{master_dir}
167
+ BACKUP_ROOT: #{backup_root}
168
+ INCLUSION
169
+ return false
170
+ end
171
+ end
172
+ true
173
+ end
174
+
175
+ def check_param_type
176
+ return true if VALUE_DELIVERY_TYPE.include?(@params[:type].to_s)
177
+
178
+ puts "Invalid delivery type: #{@params[:type]} (#{VALUE_DELIVERY_TYPE.join(' or ')})"
179
+ false
180
+ end
181
+
182
+ def check_param_argv
183
+ return true if ARGV.empty?
184
+
185
+ puts "Invalid arguments are given: #{ARGV}"
186
+ false
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'master_delivery/version'
4
+
5
+ # Deliver master files to appropriate place
6
+ module MasterDelivery
7
+ require 'fileutils'
8
+ require 'find'
9
+ require 'tmpdir'
10
+ MSG_CONFIRMATION_INTRO = <<~CONFIRM_INTRO
11
+
12
+ ** Important **
13
+ You can't undo this operation!
14
+
15
+ CONFIRM_INTRO
16
+ MSG_CONFIRMATION = <<~CONFIRMATION
17
+
18
+ Did you check that all parameters are correct? [yN]:
19
+ CONFIRMATION
20
+
21
+ # File delivery class
22
+ # 1. Move the current active files to backup/
23
+ # 2. Place a symbolic link to the master (or copy of master) in the appropriate directory
24
+ #
25
+ class MasterDelivery
26
+ attr_reader :backup_root
27
+ # @param master_root [String] Path to the dir including master dirs.
28
+ # @param backup_root [String] Path to the dir in which backup masters are created.
29
+ def initialize(master_root, backup_root = '')
30
+ @master_root = File.expand_path(master_root)
31
+ @backup_root = if backup_root.nil? || backup_root.empty?
32
+ File.expand_path(master_root + '/backup')
33
+ else
34
+ File.expand_path(backup_root)
35
+ end
36
+ end
37
+
38
+ # @param master_id [String] Top directory name of master
39
+ #
40
+ # @param target_prefix [String] Files will be delivered to this prefix location.
41
+ # If this prefix is empty, it will be placed in the root directory.
42
+ # This mechanism saves you from having to unnecessarily deepen the directory
43
+ # hierarchy under master_id.
44
+ #
45
+ # Example of prefix
46
+ # master_id: MID
47
+ # master: $master_root/MID/a/b/readme.md
48
+ # target_prefix: /Users/xxx/yyy
49
+ # delivery: /Users/xxx/yyy/a/b/readme.md
50
+ #
51
+ # Example of no-prefix
52
+ # master_id: MID
53
+ # master: $master_root/MID/a/b/readme.md
54
+ # target_prefix: (empty)
55
+ # delivery: /a/b/readme.md
56
+ #
57
+ # @param type [symbol] only link (:symbolic_link) or copy master (:regular_file)
58
+ # @param dryrun [boolean] if set this false, FileUtils::DryRun will be used.
59
+ # note: Even if dryrun: true, @backup_dir is actually created! (for name-consistency)
60
+ def deliver(master_id, target_prefix, type: :symbolic_link, dryrun: false)
61
+ FileUtils.mkdir_p(@backup_root)
62
+ utils = dryrun ? FileUtils::DryRun : FileUtils
63
+
64
+ backup_dir = Dir.mktmpdir("#{master_id}-original-", @backup_root)
65
+ master_files(master_id).each do |master|
66
+ tfile = move_to_backup(master, utils, master_id, target_prefix, backup_dir)
67
+ deliver_to_target(master, utils, tfile, type)
68
+ end
69
+ backup_dir
70
+ end
71
+
72
+ def confirm(master_id, target_prefix, type: :symbolic_link, dryrun: false)
73
+ puts MSG_CONFIRMATION_INTRO
74
+
75
+ print_params(master_id, target_prefix, type: type, dryrun: dryrun)
76
+ print_sample(master_id, target_prefix)
77
+ print MSG_CONFIRMATION.chomp # use print instead of puts for '\n'
78
+ return true if gets.chomp == 'y'
79
+
80
+ false
81
+ end
82
+
83
+ private
84
+
85
+ # Move a master file currently used to backup/
86
+ def move_to_backup(master, utils, master_id, target_prefix, backup_dir)
87
+ backupfiledir = File.dirname(backup_file_path(master, master_id, backup_dir))
88
+ utils.mkdir_p(backupfiledir)
89
+ tfile = target_file_path(master, master_id, target_prefix)
90
+ utils.mv(tfile, backupfiledir, force: true)
91
+ tfile
92
+ end
93
+
94
+ # Deliver a link to a master (or a copy of a master) in the appropriate directory
95
+ def deliver_to_target(master, utils, tfile, type)
96
+ tfiledir = File.dirname(tfile)
97
+ utils.mkdir_p(tfiledir)
98
+ case type
99
+ when :symbolic_link
100
+ utils.ln_s(master, tfiledir)
101
+ when :regular_file
102
+ utils.cp(master, tfiledir)
103
+ end
104
+ end
105
+
106
+ def print_params(master_id, target_prefix, type:, dryrun:)
107
+ mfiles = master_files(master_id)
108
+ msg = "(-m) MASTER_DIR: -m #{@master_root}/#{master_id} (#{mfiles.size} master files)\n"
109
+ msg += "(-d) DELIVER_ROOT: -d #{File.expand_path(target_prefix)}\n"
110
+ msg += "(-t) DELIVER_TYPE: -t #{type}\n"
111
+ msg += "(-b) BACKUP_ROOT: -b #{@backup_root}\n"
112
+ msg += "(-D) DRYRUN: #{dryrun ? '--dryrun' : '--no-dryrun'}\n"
113
+ puts msg
114
+ end
115
+
116
+ def print_sample(master_id, target_prefix)
117
+ mfiles = master_files(master_id)
118
+ sample_target = target_file_path(mfiles[0], master_id, target_prefix)
119
+ sample_backup = backup_file_path(mfiles[0], master_id,
120
+ @backup_root + "/#{master_id}-original-XXXX")
121
+ puts <<~SAMPLE
122
+
123
+ Sample (from #{mfiles.size} master files):
124
+ master: #{mfiles[0]}
125
+ will be delivered: #{sample_target}
126
+ and backup: #{sample_backup}
127
+ SAMPLE
128
+ end
129
+
130
+ def master_files(master_id)
131
+ Find.find("#{@master_root}/#{master_id}").select do |m|
132
+ # Reject symbolic links.
133
+ # Some "file?" and "symlink?" mothods do not work as requested
134
+ # because they are determined after following a symbolic link.
135
+ # "link.File.lstat" method does not follow symbolic links,
136
+ # so you can check if it is a symbolic or not.
137
+ File.lstat(m).file?
138
+ end
139
+ end
140
+
141
+ def relative_master_path(master, master_id)
142
+ File.expand_path(master).delete_prefix("#{@master_root}/#{master_id}")
143
+ end
144
+
145
+ def backup_file_path(master, master_id, backup_dir)
146
+ File.expand_path(backup_dir) + relative_master_path(master, master_id)
147
+ end
148
+
149
+ def target_file_path(master, master_id, target_prefix)
150
+ relative_master_path(master, master_id).prepend(File.expand_path(target_prefix))
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MasterDelivery
4
+ VERSION = '1.0.1'
5
+ DESCRIPTION = <<~DESC
6
+ Deliver all master files managed in a single master snapshot directory
7
+ into the specified directory while maintaining the hierarchy of the
8
+ master snapshot directory. If the destination file already exists,
9
+ back it up first and then deliver the master file.
10
+ DESC
11
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/master_delivery/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'master_delivery'
7
+ spec.version = MasterDelivery::VERSION
8
+ spec.authors = ['Shinya Ohtani (shinyaohtani@github)']
9
+ spec.email = ['shinya_ohtani@yahoo.co.jp']
10
+
11
+ spec.summary = 'Deliver master files to appropriate place'
12
+ spec.description = MasterDelivery::DESCRIPTION
13
+ spec.homepage = 'https://github.com/shinyaohtani/master_delivery/tree/master/README.md'
14
+ spec.license = 'MIT'
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
16
+
17
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
18
+
19
+ spec.metadata['homepage_uri'] = spec.homepage
20
+ spec.metadata['source_code_uri'] = 'https://github.com/shinyaohtani/master_delivery'
21
+ spec.metadata['changelog_uri'] = 'https://github.com/shinyaohtani/master_delivery/tree/master/CHANGELOG.md'
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ end
28
+ spec.bindir = 'exe'
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ['lib']
31
+
32
+ spec.add_development_dependency 'bundler', '~> 2.0'
33
+ spec.add_development_dependency 'github_changelog_generator', '>= 1.15.0'
34
+ spec.add_development_dependency 'pry', '>= 0.12.2'
35
+ spec.add_development_dependency 'pry-byebug', '>= 3.9.0'
36
+ spec.add_development_dependency 'rake', '>= 12.3.3'
37
+ spec.add_development_dependency 'rspec', '>= 3.9.0'
38
+ spec.add_development_dependency 'rubocop', '>= 0.80.1'
39
+ spec.add_development_dependency 'rubocop-performance', '>= 1.5.2'
40
+ spec.add_development_dependency 'rubocop-rspec', '>= 1.38.1'
41
+ end
metadata ADDED
@@ -0,0 +1,196 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: master_delivery
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Shinya Ohtani (shinyaohtani@github)
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-04-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: github_changelog_generator
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.15.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.15.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 0.12.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 0.12.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry-byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 3.9.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 3.9.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 12.3.3
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 12.3.3
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 3.9.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: 3.9.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 0.80.1
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 0.80.1
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-performance
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 1.5.2
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 1.5.2
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: 1.38.1
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: 1.38.1
139
+ description: |
140
+ Deliver all master files managed in a single master snapshot directory
141
+ into the specified directory while maintaining the hierarchy of the
142
+ master snapshot directory. If the destination file already exists,
143
+ back it up first and then deliver the master file.
144
+ email:
145
+ - shinya_ohtani@yahoo.co.jp
146
+ executables:
147
+ - master_delivery
148
+ extensions: []
149
+ extra_rdoc_files: []
150
+ files:
151
+ - ".gitignore"
152
+ - ".rspec"
153
+ - ".rubocop.yml"
154
+ - ".travis.yml"
155
+ - CHANGELOG.md
156
+ - CODE_OF_CONDUCT.md
157
+ - Gemfile
158
+ - Gemfile.lock
159
+ - LICENSE.txt
160
+ - README.md
161
+ - Rakefile
162
+ - bin/console
163
+ - bin/setup
164
+ - exe/master_delivery
165
+ - lib/cli_master_delivery.rb
166
+ - lib/master_delivery.rb
167
+ - lib/master_delivery/version.rb
168
+ - master_delivery.gemspec
169
+ homepage: https://github.com/shinyaohtani/master_delivery/tree/master/README.md
170
+ licenses:
171
+ - MIT
172
+ metadata:
173
+ allowed_push_host: https://rubygems.org
174
+ homepage_uri: https://github.com/shinyaohtani/master_delivery/tree/master/README.md
175
+ source_code_uri: https://github.com/shinyaohtani/master_delivery
176
+ changelog_uri: https://github.com/shinyaohtani/master_delivery/tree/master/CHANGELOG.md
177
+ post_install_message:
178
+ rdoc_options: []
179
+ require_paths:
180
+ - lib
181
+ required_ruby_version: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ version: 2.3.0
186
+ required_rubygems_version: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - ">="
189
+ - !ruby/object:Gem::Version
190
+ version: '0'
191
+ requirements: []
192
+ rubygems_version: 3.1.2
193
+ signing_key:
194
+ specification_version: 4
195
+ summary: Deliver master files to appropriate place
196
+ test_files: []