label_weaver 0.0.6 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dff838800cddec3836326d71abbd93a5a386f30d2fd1ef870fdd9c0e32f3d27c
4
- data.tar.gz: d4be0c5ba051a8a24ea1ed3882cd56ca72d7ec866fb39a06b61b089ad3ee7be7
3
+ metadata.gz: 8f84d950482825eab6d7306ec2ea04c3434ab0c79cb1ae0b7a836b6ff6fe4208
4
+ data.tar.gz: 56c21daba6bfd11e1d774efc734ddb03c8867fece5a63181934aef561823cf40
5
5
  SHA512:
6
- metadata.gz: 0b3f97f3dba6ded676bb59701b4cf3bb2b13a4c5c9f3b35b8b45925ae9feb106bb4028cb3fde7751e1137c088f03b3308d9627e4c9584b80ee5a12be219128e2
7
- data.tar.gz: 2a55c44f662101c8c66041a550264f0ba4ad63ed900e6850f4b67333a36023510ee2d2898c4bd2a44ac32336d66ba6ec86b7e851a1ad646d17b191ba90600515
6
+ metadata.gz: b2fb78c636d8a63f7617dffe8511b422906b63109a97074cf6f27002b94fc22c49ae8a3b8ee102e72cd0ce782e22bbab3b2c33590919aad1bd125b1c9e2069ac
7
+ data.tar.gz: 71e54ccbd1de7f76252287427741a1bcbe1af97bfad6904b21c130d226534ec63d86eca5916dbfe18b62fdb1004c64803fd1273feb7e8a64b1605924c0e2e756
data/label_weaver.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "label_weaver"
5
- spec.version = "0.0.6"
5
+ spec.version = "0.0.8"
6
6
  spec.authors = ["Stefan Exner"]
7
7
  spec.email = ["stex@stex.codes"]
8
8
  spec.homepage = "https://gitlab.com/lopo-tech/label_weaver"
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
17
17
  spec.required_ruby_version = "~> 3.3"
18
18
  spec.add_dependency "cogger", "~> 0.21"
19
19
  spec.add_dependency "containable", "~> 0.0"
20
+ spec.add_dependency "dot-properties", "~> 0.1"
20
21
  spec.add_dependency "dry-schema", "~> 1.6"
21
22
  spec.add_dependency "diffy", "~> 3.4"
22
23
  spec.add_dependency "git", "~> 2.1.1"
@@ -38,7 +38,10 @@ module LabelWeaver
38
38
  relative_filename = repo.relative_path(repository_file)
39
39
  project_file = context.project_root_dir + relative_filename
40
40
 
41
- if project_file.exist?
41
+ if repo.forced_file?(repository_file)
42
+ # If the file is forced, we need to delete the existing file if it exists.
43
+ FileUtils.rm_f(project_file) if project_file.exist?
44
+ elsif Util.file_exists?(project_file)
42
45
  if repo.timestamp_for(repository_file) > project_file.mtime
43
46
  logger.warn "File '#{relative_filename}' has a newer version in the remote repository (#{repo.timestamp_for(repository_file)} vs #{project_file.mtime})."
44
47
  end
@@ -67,7 +70,8 @@ module LabelWeaver
67
70
  context.repository_dir,
68
71
  repository_url: configuration.git[:repository],
69
72
  branch: configuration.git[:branch],
70
- excludes: configuration.excludes,
73
+ excluded_upstream_files: configuration.excluded_upstream_files,
74
+ forced_upstream_files: configuration.forced_upstream_files,
71
75
  logger: logger
72
76
  )
73
77
  end
@@ -37,13 +37,16 @@ module LabelWeaver
37
37
  relative_filename = repo.relative_path(repository_file)
38
38
  project_file = context.project_root_dir + relative_filename
39
39
 
40
- if project_file.exist?
41
- if digest(project_file) != digest(repository_file)
40
+ if repo.forced_file?(repository_file) && Util.file_exists?(project_file)
41
+ logger.debug "Force-Deleting file '#{relative_filename}'..."
42
+ project_file.unlink
43
+ remove_empty_tree(project_file.dirname)
44
+ elsif Util.file_exists?(project_file)
45
+ if Util.digest(project_file) != Util.digest(repository_file)
42
46
  logger.debug "File '#{relative_filename}' is kept as it was changed in the whitelabel project (r: #{repo.timestamp_for(repository_file)} vs w: #{project_file.mtime})."
43
47
  else
44
48
  logger.debug "Deleting file '#{relative_filename}'..."
45
49
  project_file.unlink
46
-
47
50
  remove_empty_tree(project_file.dirname)
48
51
  end
49
52
  end
@@ -68,16 +71,13 @@ module LabelWeaver
68
71
  end
69
72
  end
70
73
 
71
- def digest(file)
72
- Digest::SHA1.file(file).hexdigest
73
- end
74
-
75
74
  def repo
76
75
  @repo ||= LabelWeaver::TempRepo.new(
77
76
  context.repository_dir,
78
77
  repository_url: configuration.git[:repository],
79
78
  branch: configuration.git[:branch],
80
- excludes: configuration.excludes,
79
+ excluded_upstream_files: configuration.excluded_upstream_files,
80
+ forced_upstream_files: configuration.forced_upstream_files,
81
81
  logger: logger
82
82
  )
83
83
  end
@@ -39,7 +39,6 @@ module LabelWeaver
39
39
  else
40
40
  logger.error "Unknown format: #{context.input[:format]}"
41
41
  end
42
- logger.info context.input.inspect
43
42
  end
44
43
 
45
44
  private
@@ -57,9 +56,10 @@ module LabelWeaver
57
56
  def repo
58
57
  @repo ||= LabelWeaver::TempRepo.new(
59
58
  context.repository_dir,
60
- repository_url: configuration.git_repository,
61
- branch: configuration.git_branch,
62
- excludes: configuration.excludes,
59
+ repository_url: configuration.git[:repository],
60
+ branch: configuration.git[:branch],
61
+ excluded_upstream_files: configuration.excluded_upstream_files,
62
+ forced_upstream_files: configuration.forced_upstream_files,
63
63
  logger: logger
64
64
  )
65
65
  end
@@ -9,7 +9,8 @@ module LabelWeaver
9
9
  required(:repository).filled(:string)
10
10
  required(:branch).filled(:string)
11
11
  end
12
- optional(:excludes).array :string
12
+ optional(:excluded_upstream_files).array(:string)
13
+ optional(:forced_upstream_files).array(:string)
13
14
  optional(:hooks).hash do
14
15
  optional(:develop).hash do
15
16
  optional(:before_start).array(:string)
@@ -1,14 +1,16 @@
1
1
  git:
2
2
  repository: "git@gitlab.com:lopo-tech/label_weaver.git"
3
3
  branch: "main"
4
- # Files to exclude from the base repository, they will not be copied over to the whitelabel project.
4
+
5
+ # Files to exclude from the upstream repository, they will not be copied over to the whitelabel project.
5
6
  # Shell filename globbing rules apply, not regular expressions
6
- excludes:
7
- - .git/**
8
- hooks:
9
- develop:
10
- after_start:
11
- - echo "Development Mode Started"
7
+ #excluded_upstream_files:
8
+ # - .git/**
9
+
10
+ #hooks:
11
+ # develop:
12
+ # after_start:
13
+ # - echo "Development Mode Started"
12
14
 
13
15
  # Define files from the base and whitelabel projects that should be merged into
14
16
  # a new or existing file.
@@ -18,6 +20,13 @@ hooks:
18
20
  # target_file: package.json
19
21
  # overrides_file: package.whitelabel.json
20
22
 
23
+ # Files to be **always** taken from the upstream repository.
24
+ # They will always be copied over on development start and will be removed from the
25
+ # whitelabel project on stop.
26
+ # Shell filename globbing rules apply, not regular expressions
27
+ #forced_upstream_files:
28
+ # - test/**
29
+
21
30
  # Files here will be appended on whitelabel development instead of being skipped if the
22
31
  # file already exists in a project
23
32
  #append:
@@ -4,12 +4,13 @@ module LabelWeaver
4
4
  module Configuration
5
5
  # Defines the configuration model for use throughout the gem.
6
6
  Model = Data.define(
7
- :excludes,
7
+ :excluded_upstream_files,
8
8
  :git,
9
9
  :hooks,
10
- :merges
10
+ :merges,
11
+ :forced_upstream_files
11
12
  ) do
12
- def initialize(git:, hooks: {}, excludes: [], merges: [])
13
+ def initialize(git:, hooks: {}, excluded_upstream_files: [], forced_upstream_files: [], merges: [])
13
14
  super
14
15
  end
15
16
  end
@@ -1,3 +1,5 @@
1
+ require "dot_properties"
2
+
1
3
  module LabelWeaver
2
4
  class Merger
3
5
  include Import[:configuration, :logger]
@@ -38,7 +40,17 @@ module LabelWeaver
38
40
  source = load_file(source_file)
39
41
  overrides = load_file(overrides_file)
40
42
 
41
- write_file(target_file, source.deep_merge(overrides))
43
+ validate_compatibility!(source, overrides)
44
+
45
+ case target_file.extname
46
+ when ".properties"
47
+ overrides.to_h.each do |k, v|
48
+ source[k] = v
49
+ end
50
+ write_file(target_file, source)
51
+ else
52
+ write_file(target_file, source.deep_merge(overrides))
53
+ end
42
54
  end
43
55
 
44
56
  def restore_file(relative_file_path)
@@ -52,8 +64,23 @@ module LabelWeaver
52
64
  configuration.merges.map { _1.transform_keys(&:to_sym) }
53
65
  end
54
66
 
67
+ def validate_compatibility!(source, overrides)
68
+ # Check for property files
69
+ if source.is_a?(DotProperties) || overrides.is_a?(DotProperties)
70
+ if nested_hash?(source) || nested_hash?(overrides)
71
+ raise ArgumentError, "Property files can only be merged with other property files or one-dimensional hashes"
72
+ end
73
+ end
74
+ end
75
+
76
+ def nested_hash?(value)
77
+ value.is_a?(Hash) && value.values.any? { |v| v.is_a?(Hash) }
78
+ end
79
+
55
80
  def load_file(file)
56
81
  case file.extname
82
+ when ".properties"
83
+ DotProperties.load(file)
57
84
  when ".yaml", ".yml"
58
85
  YAML.load_file(file)
59
86
  when ".json"
@@ -65,10 +92,13 @@ module LabelWeaver
65
92
 
66
93
  def write_file(file, content)
67
94
  case file.extname
95
+ when ".properties"
96
+ # TODO: Handle content that is not already a DotProperties instance
97
+ File.write(file, content.to_s)
68
98
  when ".yaml", ".yml"
69
- File.write(file, content.to_yaml)
99
+ File.write(file, content.to_h.to_yaml)
70
100
  when ".json"
71
- File.write(file, JSON.pretty_generate(content))
101
+ File.write(file, JSON.pretty_generate(content.to_h))
72
102
  else
73
103
  raise ArgumentError, "Unsupported file type: #{file.extname}"
74
104
  end
@@ -7,13 +7,21 @@ module LabelWeaver
7
7
  class TempRepo
8
8
  using Refinements::Pathname
9
9
 
10
- attr_reader :repository_path, :repository_url, :branch, :excludes, :logger
11
-
12
- def initialize(repository_path, repository_url:, branch: "main", excludes: [], logger: Logger.new($stdout))
10
+ attr_reader :repository_path, :repository_url, :branch, :logger, :excluded_upstream_files, :forced_upstream_files
11
+
12
+ def initialize(
13
+ repository_path,
14
+ repository_url:,
15
+ branch: "main",
16
+ excluded_upstream_files: [],
17
+ forced_upstream_files: [],
18
+ logger: Logger.new($stdout)
19
+ )
13
20
  @repository_path = repository_path
14
21
  @repository_url = repository_url
15
22
  @branch = branch
16
- @excludes = excludes + %w[. ..]
23
+ @excluded_upstream_files = excluded_upstream_files + %w[. ..]
24
+ @forced_upstream_files = forced_upstream_files
17
25
  @logger = logger
18
26
  end
19
27
 
@@ -27,7 +35,7 @@ module LabelWeaver
27
35
  end
28
36
 
29
37
  def digest_for(file)
30
- Digest::SHA1.file(file).hexdigest
38
+ Util.digest(file)
31
39
  end
32
40
 
33
41
  def changed_file?(repository_file, project_root_dir:)
@@ -60,12 +68,26 @@ module LabelWeaver
60
68
  def relevant_files
61
69
  files.filter do |file|
62
70
  # Reject any files that are set up to be excluded. Shell filename globbing rules apply
63
- next false if excludes.any? { relative_path(file).fnmatch?(_1, File::FNM_DOTMATCH) }
71
+ next false if excluded_file?(file)
64
72
 
65
73
  true
66
74
  end
67
75
  end
68
76
 
77
+ #
78
+ # @return [Boolean] +true+ if the file should never be copied over from the repository
79
+ #
80
+ def excluded_file?(repository_file)
81
+ excluded_upstream_files.any? { relative_path(repository_file).fnmatch?(_1, File::FNM_DOTMATCH) }
82
+ end
83
+
84
+ #
85
+ # @return [Boolean] +true+ if the file should **always** be copied over from the repository
86
+ #
87
+ def forced_file?(repository_file)
88
+ forced_upstream_files.any? { relative_path(repository_file).fnmatch?(_1, File::FNM_DOTMATCH) }
89
+ end
90
+
69
91
  #
70
92
  # Updates the atime and mtime of each file in the repository to their latest commit time
71
93
  # TODO: Check if still needed
@@ -103,7 +125,9 @@ module LabelWeaver
103
125
  # @return [Array<Pathname>] All files inside the repository, including dotfiles. No folders.
104
126
  #
105
127
  def files
106
- repository_path.glob("**/*", File::FNM_DOTMATCH).select(&:file?)
128
+ # The symlink check is necessary to include directory symlinks, but leave out
129
+ # regular directories
130
+ repository_path.glob("**/*", File::FNM_DOTMATCH).select { _1.file? || _1.symlink? }
107
131
  end
108
132
 
109
133
  def repo
@@ -0,0 +1,18 @@
1
+ module LabelWeaver
2
+ module Util
3
+ def digest(file)
4
+ if file.symlink?
5
+ # for symlinks we just use the target path
6
+ file.readlink
7
+ else
8
+ Digest::SHA1.file(file).hexdigest
9
+ end
10
+ end
11
+ module_function :digest
12
+
13
+ def file_exists?(file)
14
+ file.symlink? || file.exist?
15
+ end
16
+ module_function :file_exists?
17
+ end
18
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: label_weaver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Exner
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-06 00:00:00.000000000 Z
11
+ date: 2024-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cogger
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dot-properties
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.1'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: dry-schema
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -236,6 +250,7 @@ files:
236
250
  - lib/label_weaver/import.rb
237
251
  - lib/label_weaver/merger.rb
238
252
  - lib/label_weaver/temp_repo.rb
253
+ - lib/label_weaver/util.rb
239
254
  homepage: https://gitlab.com/lopo-tech/label_weaver
240
255
  licenses:
241
256
  - MIT