label_weaver 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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