label_weaver 0.0.3
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 +7 -0
- data/README.md +3 -0
- data/exe/label_weaver +7 -0
- data/label_weaver.gemspec +38 -0
- data/lib/label_weaver/cli/actions/develop/start.rb +65 -0
- data/lib/label_weaver/cli/actions/develop/stop.rb +77 -0
- data/lib/label_weaver/cli/actions/diff/file.rb +19 -0
- data/lib/label_weaver/cli/actions/diff/format.rb +19 -0
- data/lib/label_weaver/cli/actions/init.rb +48 -0
- data/lib/label_weaver/cli/actions/prepare_base_project.rb +30 -0
- data/lib/label_weaver/cli/commands/develop.rb +16 -0
- data/lib/label_weaver/cli/commands/diff.rb +69 -0
- data/lib/label_weaver/cli/shell.rb +50 -0
- data/lib/label_weaver/configuration/contract.rb +15 -0
- data/lib/label_weaver/configuration/defaults.yml +12 -0
- data/lib/label_weaver/configuration/model.rb +12 -0
- data/lib/label_weaver/container.rb +30 -0
- data/lib/label_weaver/import.rb +7 -0
- data/lib/label_weaver/temp_repo.rb +111 -0
- data/lib/label_weaver.rb +18 -0
- metadata +276 -0
    
        checksums.yaml
    ADDED
    
    | @@ -0,0 +1,7 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: 8d4577814ad253da907628f3c86300dc89c2b362260fa6772af602670ce2aa63
         | 
| 4 | 
            +
              data.tar.gz: a262362d186dca07c7789baca7cd642c3d9b43e5ea1ca3ec6259ac4a244ef90f
         | 
| 5 | 
            +
            SHA512:
         | 
| 6 | 
            +
              metadata.gz: 64c146c67e07cb609d4c7ac458e37d071edd0e592ec460f3b692b559a5121b2dfa12c5294a71eb565cb7d2064d54053aae8a0cf09ccdae2fc94fe48f4970cbcd
         | 
| 7 | 
            +
              data.tar.gz: 17f74363825bd9115228468d77b175b19c2895a680acd3809e0a7d25f3dda1338cae90e660fd26140fc57b78cd6aff80dd99f405938141d46cfcb5d56104d131
         | 
    
        data/README.md
    ADDED
    
    
    
        data/exe/label_weaver
    ADDED
    
    
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Gem::Specification.new do |spec|
         | 
| 4 | 
            +
              spec.name = "label_weaver"
         | 
| 5 | 
            +
              spec.version = "0.0.3"
         | 
| 6 | 
            +
              spec.authors = ["Stefan Exner"]
         | 
| 7 | 
            +
              spec.email = ["stex@stex.codes"]
         | 
| 8 | 
            +
              spec.homepage = "https://gitlab.com/lopo-tech/label_weaver"
         | 
| 9 | 
            +
              spec.summary = "Helper tool to manage whitelabel version of base projects"
         | 
| 10 | 
            +
              spec.license = "MIT"
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              spec.metadata = {
         | 
| 13 | 
            +
                "label" => "LabelWeaver",
         | 
| 14 | 
            +
                "rubygems_mfa_required" => "true"
         | 
| 15 | 
            +
              }
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              spec.required_ruby_version = "~> 3.3"
         | 
| 18 | 
            +
              spec.add_dependency "cogger", "~> 0.21"
         | 
| 19 | 
            +
              spec.add_dependency "containable", "~> 0.0"
         | 
| 20 | 
            +
              spec.add_dependency "dry-monads", "~> 1.6"
         | 
| 21 | 
            +
              spec.add_dependency "dry-schema", "~> 1.6"
         | 
| 22 | 
            +
              spec.add_dependency "diffy", "~> 3.4"
         | 
| 23 | 
            +
              spec.add_dependency "etcher", "~> 1.6"
         | 
| 24 | 
            +
              spec.add_dependency "git", "~> 2.1.1"
         | 
| 25 | 
            +
              spec.add_dependency "infusible", "~> 3.5"
         | 
| 26 | 
            +
              spec.add_dependency "ruby-next-core", "~> 1.0"
         | 
| 27 | 
            +
              spec.add_dependency "runcom", "~> 11.0"
         | 
| 28 | 
            +
              spec.add_dependency "sod", "~> 0.8"
         | 
| 29 | 
            +
              spec.add_dependency "spek", "~> 3.0"
         | 
| 30 | 
            +
              spec.add_dependency "tty-file", "~> 0.10"
         | 
| 31 | 
            +
              spec.add_dependency "tty-pager", "~> 0.14"
         | 
| 32 | 
            +
              spec.add_dependency "zeitwerk", "~> 2.6"
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              spec.bindir = "exe"
         | 
| 35 | 
            +
              spec.executables << "label_weaver"
         | 
| 36 | 
            +
              spec.extra_rdoc_files = Dir["README*", "LICENSE*"]
         | 
| 37 | 
            +
              spec.files = Dir["*.gemspec", "lib/**/*"]
         | 
| 38 | 
            +
            end
         | 
| @@ -0,0 +1,65 @@ | |
| 1 | 
            +
            require "git"
         | 
| 2 | 
            +
            require "yaml"
         | 
| 3 | 
            +
            require "digest"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module LabelWeaver
         | 
| 6 | 
            +
              module CLI
         | 
| 7 | 
            +
                module Actions
         | 
| 8 | 
            +
                  module Develop
         | 
| 9 | 
            +
                    class Start < Sod::Action
         | 
| 10 | 
            +
                      include Import[:kernel, :configuration, :xdg_config, :logger]
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                      using Refinements::Pathname
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                      description "Starts whitelabel development mode"
         | 
| 15 | 
            +
                      ancillary "Fetches the latest git changes and syncs them with your local branch."
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                      on %w[--start]
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                      def call(*args)
         | 
| 20 | 
            +
                        unless xdg_config.active
         | 
| 21 | 
            +
                          logger.error("No configuration found. Are you in the correct directory?")
         | 
| 22 | 
            +
                          kernel.exit(1)
         | 
| 23 | 
            +
                        end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                        repo.clone_or_update
         | 
| 26 | 
            +
                        copy_repository_files
         | 
| 27 | 
            +
                      end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                      private
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                      def copy_repository_files
         | 
| 32 | 
            +
                        logger.info "Copying repository files to whitelabel project..."
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                        repo.relevant_files.each do |repository_file|
         | 
| 35 | 
            +
                          relative_filename = repo.relative_path(repository_file)
         | 
| 36 | 
            +
                          project_file = context.project_root_dir + relative_filename
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                          if project_file.exist?
         | 
| 39 | 
            +
                            if repo.timestamp_for(repository_file) > project_file.mtime
         | 
| 40 | 
            +
                              logger.warn "File '#{relative_filename}' has a newer version in the remote repository (#{repo.timestamp_for(repository_file)} vs #{project_file.mtime})."
         | 
| 41 | 
            +
                            end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                            logger.debug "Skipping '#{relative_filename}'..."
         | 
| 44 | 
            +
                            next
         | 
| 45 | 
            +
                          end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                          FileUtils.mkdir_p(project_file.dirname)
         | 
| 48 | 
            +
                          FileUtils.copy(repository_file, project_file, preserve: true)
         | 
| 49 | 
            +
                        end
         | 
| 50 | 
            +
                      end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                      def repo
         | 
| 53 | 
            +
                        @repo ||= LabelWeaver::TempRepo.new(
         | 
| 54 | 
            +
                          context.repository_dir,
         | 
| 55 | 
            +
                          repository_url: configuration.git_repository,
         | 
| 56 | 
            +
                          branch: configuration.git_branch,
         | 
| 57 | 
            +
                          excludes: configuration.excludes,
         | 
| 58 | 
            +
                          logger: logger
         | 
| 59 | 
            +
                        )
         | 
| 60 | 
            +
                      end
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
            end
         | 
| @@ -0,0 +1,77 @@ | |
| 1 | 
            +
            require "git"
         | 
| 2 | 
            +
            require "yaml"
         | 
| 3 | 
            +
            require "digest"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module LabelWeaver
         | 
| 6 | 
            +
              module CLI
         | 
| 7 | 
            +
                module Actions
         | 
| 8 | 
            +
                  module Develop
         | 
| 9 | 
            +
                    class Stop < Sod::Action
         | 
| 10 | 
            +
                      include Import[:configuration, :xdg_config, :kernel, :logger]
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                      using Refinements::Pathname
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                      description "Stops whitelabel development mode"
         | 
| 15 | 
            +
                      ancillary "Removes all unchanged files from the whitelabel project again."
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                      on %w[--stop]
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                      def call(*args)
         | 
| 20 | 
            +
                        unless xdg_config.active
         | 
| 21 | 
            +
                          logger.error("No configuration found. Are you in the correct directory?")
         | 
| 22 | 
            +
                          kernel.exit(1)
         | 
| 23 | 
            +
                        end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                        remove_base_files
         | 
| 26 | 
            +
                      end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                      private
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                      def remove_base_files
         | 
| 31 | 
            +
                        logger.info "Removing unchanged base files from whitelabel project"
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                        repo.relevant_files.each do |repository_file|
         | 
| 34 | 
            +
                          relative_filename = repo.relative_path(repository_file)
         | 
| 35 | 
            +
                          project_file = context.project_root_dir + relative_filename
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                          if project_file.exist?
         | 
| 38 | 
            +
                            # TODO: Should we get a time component in here to check for possible newer base repo files?
         | 
| 39 | 
            +
                            if digest(project_file) != digest(repository_file)
         | 
| 40 | 
            +
                              logger.info "File '#{relative_filename}' is kept as it was changed in the whitelabel project (r: #{repo.timestamp_for(repository_file)} vs w: #{project_file.mtime})."
         | 
| 41 | 
            +
                            else
         | 
| 42 | 
            +
                              logger.debug "Deleting file '#{relative_filename}'..."
         | 
| 43 | 
            +
                              project_file.unlink
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                              remove_empty_tree(project_file.dirname)
         | 
| 46 | 
            +
                            end
         | 
| 47 | 
            +
                          end
         | 
| 48 | 
            +
                        end
         | 
| 49 | 
            +
                      end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                      def remove_empty_tree(dir)
         | 
| 52 | 
            +
                        return unless dir.empty?
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                        logger.debug "Deleting empty directory '#{dir}'..."
         | 
| 55 | 
            +
                        dir.unlink
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                        remove_empty_tree(dir.parent)
         | 
| 58 | 
            +
                      end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                      def digest(file)
         | 
| 61 | 
            +
                        Digest::SHA1.file(file).hexdigest
         | 
| 62 | 
            +
                      end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                      def repo
         | 
| 65 | 
            +
                        @repo ||= LabelWeaver::TempRepo.new(
         | 
| 66 | 
            +
                          context.repository_dir,
         | 
| 67 | 
            +
                          repository_url: configuration.git_repository,
         | 
| 68 | 
            +
                          branch: configuration.git_branch,
         | 
| 69 | 
            +
                          excludes: configuration.excludes,
         | 
| 70 | 
            +
                          logger: logger
         | 
| 71 | 
            +
                        )
         | 
| 72 | 
            +
                      end
         | 
| 73 | 
            +
                    end
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            module LabelWeaver
         | 
| 2 | 
            +
              module CLI
         | 
| 3 | 
            +
                module Actions
         | 
| 4 | 
            +
                  module Diff
         | 
| 5 | 
            +
                    class File < Sod::Action
         | 
| 6 | 
            +
                      using Refinements::Pathname
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                      description "Shows a diff for a single chosen file. Expects a path relative to the project root."
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                      on %w[-f --file], argument: "PATH", type: String
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                      def call(path)
         | 
| 13 | 
            +
                        context.input[:file] = Pathname.new(path)
         | 
| 14 | 
            +
                      end
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            module LabelWeaver
         | 
| 2 | 
            +
              module CLI
         | 
| 3 | 
            +
                module Actions
         | 
| 4 | 
            +
                  module Diff
         | 
| 5 | 
            +
                    class Format < Sod::Action
         | 
| 6 | 
            +
                      using Refinements::Pathname
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                      description "Choose the format to be used when displaying the diff."
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                      on %w[--format], argument: "FORMAT", type: String, allow: %w[unified patch]
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                      def call(diff_format)
         | 
| 13 | 
            +
                        context.input[:format] = diff_format
         | 
| 14 | 
            +
                      end
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
| @@ -0,0 +1,48 @@ | |
| 1 | 
            +
            require "tty/file"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module LabelWeaver
         | 
| 4 | 
            +
              module CLI
         | 
| 5 | 
            +
                module Actions
         | 
| 6 | 
            +
                  class Init < Sod::Action
         | 
| 7 | 
            +
                    include Import[:kernel, :logger]
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    using Refinements::Pathname
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    on "--init"
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    description "Initializes a new whitelabel project"
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    def call(*)
         | 
| 16 | 
            +
                      create_config
         | 
| 17 | 
            +
                      create_gitignore
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    private
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    def create_config
         | 
| 23 | 
            +
                      xdg_config = context[xdg_config, :xdg_config]
         | 
| 24 | 
            +
                      defaults_path = Pathname.new(context[defaults_path, :defaults_path])
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                      path = xdg_config.local
         | 
| 27 | 
            +
                      path_info = path.to_s.inspect
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                      if path.exist?
         | 
| 30 | 
            +
                        logger.warn { "Skipped. Configuration exists: #{path_info}." }
         | 
| 31 | 
            +
                      else
         | 
| 32 | 
            +
                        defaults_path.copy path.make_ancestors
         | 
| 33 | 
            +
                        logger.info { "Created: #{path_info}." }
         | 
| 34 | 
            +
                      end
         | 
| 35 | 
            +
                    end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    def create_gitignore
         | 
| 38 | 
            +
                      TTY::File.create_file(gitignore)
         | 
| 39 | 
            +
                      TTY::File.append_to_file(gitignore, "repository", force: false)
         | 
| 40 | 
            +
                    end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    def gitignore
         | 
| 43 | 
            +
                      context.local_tmp_dir + ".gitignore"
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            require "tty/file"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module LabelWeaver
         | 
| 4 | 
            +
              module CLI
         | 
| 5 | 
            +
                module Actions
         | 
| 6 | 
            +
                  class PrepareBaseProject < Sod::Action
         | 
| 7 | 
            +
                    include Import[:kernel, :logger]
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    on "--prepare-base-project"
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    description "Adjusts certain files in a project to be used as base for whitelabel projects."
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    def call(*)
         | 
| 14 | 
            +
                      adjust_dockerignore
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    private
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                    def adjust_dockerignore
         | 
| 20 | 
            +
                      TTY::File.create_file(dockerignore) unless dockerignore.exist?
         | 
| 21 | 
            +
                      TTY::File.append_to_file(dockerignore, ".config/label_weaver")
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    def dockerignore
         | 
| 25 | 
            +
                      context.project_root_dir + ".dockerignore"
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            module LabelWeaver
         | 
| 2 | 
            +
              module CLI
         | 
| 3 | 
            +
                module Commands
         | 
| 4 | 
            +
                  class Develop < Sod::Command
         | 
| 5 | 
            +
                    include Import[:kernel, :logger]
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                    handle "develop"
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    description "Start / Stop whitelabel development mode"
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    on(::LabelWeaver::CLI::Actions::Develop::Start)
         | 
| 12 | 
            +
                    on(::LabelWeaver::CLI::Actions::Develop::Stop)
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,69 @@ | |
| 1 | 
            +
            require "tty/pager"
         | 
| 2 | 
            +
            require "diffy"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module LabelWeaver
         | 
| 5 | 
            +
              module CLI
         | 
| 6 | 
            +
                module Commands
         | 
| 7 | 
            +
                  class Diff < Sod::Command
         | 
| 8 | 
            +
                    include Import[:kernel, :logger, :configuration]
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    handle "diff"
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    description "Shows difference between the base repository and the local files "
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    on(::LabelWeaver::CLI::Actions::Diff::Format)
         | 
| 15 | 
            +
                    on(::LabelWeaver::CLI::Actions::Diff::File)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    def call(*)
         | 
| 18 | 
            +
                      @file_path = context.input[:file]
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                      case context.input[:format] || "unified"
         | 
| 21 | 
            +
                      when "unified"
         | 
| 22 | 
            +
                        TTY::Pager.page do |pager|
         | 
| 23 | 
            +
                          changed_files.each do |repository_file, project_file|
         | 
| 24 | 
            +
                            pager.write <<~EOS
         | 
| 25 | 
            +
                              
         | 
| 26 | 
            +
                              #{"*" * (project_file.to_s.length + 4)}
         | 
| 27 | 
            +
                              * #{project_file} *
         | 
| 28 | 
            +
                              #{"*" * (project_file.to_s.length + 4)}
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                            EOS
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                            pager.write Diffy::Diff.new(repository_file.to_s, project_file.to_s, source: "files", context: 3).to_s(:color)
         | 
| 33 | 
            +
                          end
         | 
| 34 | 
            +
                        end
         | 
| 35 | 
            +
                      when "patch"
         | 
| 36 | 
            +
                        changed_files.each do |repository_file, project_file|
         | 
| 37 | 
            +
                          puts Diffy::Diff.new(repository_file.to_s, project_file.to_s, source: "files", context: 0, include_diff_info: true)
         | 
| 38 | 
            +
                        end
         | 
| 39 | 
            +
                      else
         | 
| 40 | 
            +
                        logger.error "Unknown format: #{context.input[:format]}"
         | 
| 41 | 
            +
                      end
         | 
| 42 | 
            +
                      logger.info context.input.inspect
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                    private
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    def changed_files
         | 
| 48 | 
            +
                      repo.relevant_files_with_project_files(project_root_dir: context.project_root_dir).filter_map do |repository_file, project_file|
         | 
| 49 | 
            +
                        next unless project_file.exist?
         | 
| 50 | 
            +
                        next unless repo.changed_file?(repository_file, project_root_dir: context.project_root_dir)
         | 
| 51 | 
            +
                        next if @file_path && project_file != context.project_root_dir + @file_path
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                        [repository_file, project_file]
         | 
| 54 | 
            +
                      end
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    def repo
         | 
| 58 | 
            +
                      @repo ||= LabelWeaver::TempRepo.new(
         | 
| 59 | 
            +
                        context.repository_dir,
         | 
| 60 | 
            +
                        repository_url: configuration.git_repository,
         | 
| 61 | 
            +
                        branch: configuration.git_branch,
         | 
| 62 | 
            +
                        excludes: configuration.excludes,
         | 
| 63 | 
            +
                        logger: logger
         | 
| 64 | 
            +
                      )
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
            end
         | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "sod"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module LabelWeaver
         | 
| 6 | 
            +
              module CLI
         | 
| 7 | 
            +
                # The main Command Line Interface (CLI) object.
         | 
| 8 | 
            +
                class Shell
         | 
| 9 | 
            +
                  include Import[:defaults_path, :xdg_config, :specification]
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def initialize(context: Sod::Context, dsl: Sod, **)
         | 
| 12 | 
            +
                    super(**)
         | 
| 13 | 
            +
                    @context = context
         | 
| 14 | 
            +
                    @dsl = dsl
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def call(...) = cli.call(...)
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  private
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  attr_reader :context, :dsl
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def cli
         | 
| 24 | 
            +
                    context = build_context
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    dsl.new :label_weaver, banner: specification.banner do
         | 
| 27 | 
            +
                      on(::LabelWeaver::CLI::Actions::Init, context:)
         | 
| 28 | 
            +
                      on(::LabelWeaver::CLI::Actions::PrepareBaseProject, context:)
         | 
| 29 | 
            +
                      on(::LabelWeaver::CLI::Commands::Develop, context:)
         | 
| 30 | 
            +
                      on(::LabelWeaver::CLI::Commands::Diff, context:)
         | 
| 31 | 
            +
                      on(Sod::Prefabs::Actions::Version, context:)
         | 
| 32 | 
            +
                      on(Sod::Prefabs::Actions::Help, self)
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def build_context
         | 
| 37 | 
            +
                    context[
         | 
| 38 | 
            +
                      input: {},
         | 
| 39 | 
            +
                      project_root_dir: Pathname.new(Dir.pwd),
         | 
| 40 | 
            +
                      local_tmp_dir: Pathname.new(Dir.pwd).join(".config", "label_weaver"),
         | 
| 41 | 
            +
                      repository_dir: Pathname.new(Dir.pwd).join(".config", "label_weaver", "repository"),
         | 
| 42 | 
            +
                      tracking_file: Pathname.new(Dir.pwd).join(".config", "label_weaver", "files.yml"),
         | 
| 43 | 
            +
                      defaults_path:,
         | 
| 44 | 
            +
                      xdg_config:,
         | 
| 45 | 
            +
                      version_label: specification.labeled_version
         | 
| 46 | 
            +
                    ]
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "dry/schema"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Dry::Schema.load_extensions :monads
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module LabelWeaver
         | 
| 8 | 
            +
              module Configuration
         | 
| 9 | 
            +
                Contract = Dry::Schema.Params do
         | 
| 10 | 
            +
                  required(:git_repository).filled :string
         | 
| 11 | 
            +
                  required(:git_branch).filled :string
         | 
| 12 | 
            +
                  optional(:excludes).array :string
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            git:
         | 
| 2 | 
            +
              repository: "git@gitlab.com:lopo-tech/label_weaver.git"
         | 
| 3 | 
            +
              branch: "main"
         | 
| 4 | 
            +
            # Files to exclude from the base repository, they will not be copied over to the whitelabel project.
         | 
| 5 | 
            +
            # Shell filename globbing rules apply, not regular expressions
         | 
| 6 | 
            +
            excludes:
         | 
| 7 | 
            +
              - .git/**
         | 
| 8 | 
            +
            # Files here will be appended on whitelabel development instead of being skipped if the
         | 
| 9 | 
            +
            # file already exists in a project
         | 
| 10 | 
            +
            #append:
         | 
| 11 | 
            +
            #  - .gitignore
         | 
| 12 | 
            +
            #  - .dockerignore
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "cogger"
         | 
| 4 | 
            +
            require "containable"
         | 
| 5 | 
            +
            require "etcher"
         | 
| 6 | 
            +
            require "runcom"
         | 
| 7 | 
            +
            require "spek"
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            module LabelWeaver
         | 
| 10 | 
            +
              # Provides a global gem container for injection into other objects.
         | 
| 11 | 
            +
              module Container
         | 
| 12 | 
            +
                extend Containable
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                register :configuration do
         | 
| 15 | 
            +
                  self[:defaults].add_loader(:yaml, self[:xdg_config].active)
         | 
| 16 | 
            +
                    .then { |registry| Etcher.call registry }
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                register :defaults do
         | 
| 20 | 
            +
                  Etcher::Registry.new(contract: Configuration::Contract, model: Configuration::Model)
         | 
| 21 | 
            +
                    .add_loader(:yaml, self[:defaults_path])
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                register(:specification) { Spek::Loader.call "#{__dir__}/../../label_weaver.gemspec" }
         | 
| 25 | 
            +
                register(:defaults_path) { Pathname(__dir__).join("configuration/defaults.yml") }
         | 
| 26 | 
            +
                register(:xdg_config) { Runcom::Config.new("label_weaver/configuration.yml") }
         | 
| 27 | 
            +
                register(:logger) { Cogger.new(id: "label_weaver") }
         | 
| 28 | 
            +
                register :kernel, Kernel
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,111 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "git"
         | 
| 4 | 
            +
            require "digest"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module LabelWeaver
         | 
| 7 | 
            +
              class TempRepo
         | 
| 8 | 
            +
                using Refinements::Pathname
         | 
| 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))
         | 
| 13 | 
            +
                  @repository_path = repository_path
         | 
| 14 | 
            +
                  @repository_url = repository_url
         | 
| 15 | 
            +
                  @branch = branch
         | 
| 16 | 
            +
                  @excludes = excludes + %w[. ..]
         | 
| 17 | 
            +
                  @logger = logger
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                #
         | 
| 21 | 
            +
                # @return [Time] the last time the file was part of a commit, closest we can get to an mtime
         | 
| 22 | 
            +
                #
         | 
| 23 | 
            +
                def timestamp_for(file)
         | 
| 24 | 
            +
                  repo.log(1).path(file).first.date
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def digest_for(file)
         | 
| 28 | 
            +
                  Digest::SHA1.file(file).hexdigest
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def changed_file?(repository_file, project_root_dir:)
         | 
| 32 | 
            +
                  digest_for(repository_file) != digest_for(project_root_dir + relative_path(repository_file))
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                #
         | 
| 36 | 
            +
                # Clones the repository if it doesn't exist yet locally or fetches the latest updates
         | 
| 37 | 
            +
                #
         | 
| 38 | 
            +
                def clone_or_update
         | 
| 39 | 
            +
                  if repository_path.exist?
         | 
| 40 | 
            +
                    logger.info "Pulling latest changes from remote repository (#{repository_url})..."
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    repo.pull("origin", branch)
         | 
| 43 | 
            +
                  else
         | 
| 44 | 
            +
                    logger.info "Cloning remote repository, this might take a while..."
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    Git.clone(
         | 
| 47 | 
            +
                      repository_url,
         | 
| 48 | 
            +
                      repository_path.basename,
         | 
| 49 | 
            +
                      path: repository_path.parent,
         | 
| 50 | 
            +
                      branch:
         | 
| 51 | 
            +
                    )
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                #
         | 
| 56 | 
            +
                # @return [Array<Pathname>] All repository files that are not set to be excluded
         | 
| 57 | 
            +
                #
         | 
| 58 | 
            +
                def relevant_files
         | 
| 59 | 
            +
                  files.filter do |file|
         | 
| 60 | 
            +
                    # Reject any files that are set up to be excluded. Shell filename globbing rules apply
         | 
| 61 | 
            +
                    next false if excludes.any? { relative_path(file).fnmatch?(_1, File::FNM_DOTMATCH) }
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    true
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                #
         | 
| 68 | 
            +
                # Updates the atime and mtime of each file in the repository to their latest commit time
         | 
| 69 | 
            +
                # TODO: Check if still needed
         | 
| 70 | 
            +
                #
         | 
| 71 | 
            +
                def update_repository_timestamps
         | 
| 72 | 
            +
                  logger.info "Updating repository timestamps..."
         | 
| 73 | 
            +
                  repository_path.glob("**/*", File::FNM_DOTMATCH).each do |file|
         | 
| 74 | 
            +
                    # Set the file modification times to the last time they were updated in a commit
         | 
| 75 | 
            +
                    time = repo.all.log.path(file).first.date
         | 
| 76 | 
            +
                    file.utime(time, time)
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                #
         | 
| 81 | 
            +
                # @return [Pathname] the filename relative to the git repository root
         | 
| 82 | 
            +
                #
         | 
| 83 | 
            +
                def relative_path(filename)
         | 
| 84 | 
            +
                  filename.relative_path_from(repository_path)
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                #
         | 
| 88 | 
            +
                # @return [Array<Array<Pathname, Pathname>>] all relevant repository files with their corresponding
         | 
| 89 | 
            +
                #   path within the project
         | 
| 90 | 
            +
                #
         | 
| 91 | 
            +
                def relevant_files_with_project_files(project_root_dir:)
         | 
| 92 | 
            +
                  relevant_files.map do |repository_file|
         | 
| 93 | 
            +
                    relative_filename = relative_path(repository_file)
         | 
| 94 | 
            +
                    [repository_file, project_root_dir + relative_filename]
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                private
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                #
         | 
| 101 | 
            +
                # @return [Array<Pathname>] All files inside the repository, including dotfiles. No folders.
         | 
| 102 | 
            +
                #
         | 
| 103 | 
            +
                def files
         | 
| 104 | 
            +
                  repository_path.glob("**/*", File::FNM_DOTMATCH).select(&:file?)
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                def repo
         | 
| 108 | 
            +
                  @repo ||= Git.open(repository_path)
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
              end
         | 
| 111 | 
            +
            end
         | 
    
        data/lib/label_weaver.rb
    ADDED
    
    | @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require "zeitwerk"
         | 
| 4 | 
            +
            require "ruby-next"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Zeitwerk::Loader.new.then do |loader|
         | 
| 7 | 
            +
              loader.inflector.inflect "cli" => "CLI"
         | 
| 8 | 
            +
              loader.tag = File.basename __FILE__, ".rb"
         | 
| 9 | 
            +
              loader.push_dir __dir__
         | 
| 10 | 
            +
              loader.setup
         | 
| 11 | 
            +
            end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            # Main namespace.
         | 
| 14 | 
            +
            module LabelWeaver
         | 
| 15 | 
            +
              def self.loader(registry = Zeitwerk::Registry)
         | 
| 16 | 
            +
                @loader ||= registry.loaders.find { |loader| loader.tag == File.basename(__FILE__, ".rb") }
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,276 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: label_weaver
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 0.0.3
         | 
| 5 | 
            +
            platform: ruby
         | 
| 6 | 
            +
            authors:
         | 
| 7 | 
            +
            - Stefan Exner
         | 
| 8 | 
            +
            autorequire:
         | 
| 9 | 
            +
            bindir: exe
         | 
| 10 | 
            +
            cert_chain: []
         | 
| 11 | 
            +
            date: 2024-08-27 00:00:00.000000000 Z
         | 
| 12 | 
            +
            dependencies:
         | 
| 13 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            +
              name: cogger
         | 
| 15 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            +
                requirements:
         | 
| 17 | 
            +
                - - "~>"
         | 
| 18 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            +
                    version: '0.21'
         | 
| 20 | 
            +
              type: :runtime
         | 
| 21 | 
            +
              prerelease: false
         | 
| 22 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            +
                requirements:
         | 
| 24 | 
            +
                - - "~>"
         | 
| 25 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            +
                    version: '0.21'
         | 
| 27 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            +
              name: containable
         | 
| 29 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 | 
            +
                requirements:
         | 
| 31 | 
            +
                - - "~>"
         | 
| 32 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            +
                    version: '0.0'
         | 
| 34 | 
            +
              type: :runtime
         | 
| 35 | 
            +
              prerelease: false
         | 
| 36 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 | 
            +
                requirements:
         | 
| 38 | 
            +
                - - "~>"
         | 
| 39 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            +
                    version: '0.0'
         | 
| 41 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            +
              name: dry-monads
         | 
| 43 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            +
                requirements:
         | 
| 45 | 
            +
                - - "~>"
         | 
| 46 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            +
                    version: '1.6'
         | 
| 48 | 
            +
              type: :runtime
         | 
| 49 | 
            +
              prerelease: false
         | 
| 50 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            +
                requirements:
         | 
| 52 | 
            +
                - - "~>"
         | 
| 53 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            +
                    version: '1.6'
         | 
| 55 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            +
              name: dry-schema
         | 
| 57 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - "~>"
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '1.6'
         | 
| 62 | 
            +
              type: :runtime
         | 
| 63 | 
            +
              prerelease: false
         | 
| 64 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 | 
            +
                requirements:
         | 
| 66 | 
            +
                - - "~>"
         | 
| 67 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            +
                    version: '1.6'
         | 
| 69 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 70 | 
            +
              name: diffy
         | 
| 71 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 72 | 
            +
                requirements:
         | 
| 73 | 
            +
                - - "~>"
         | 
| 74 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 75 | 
            +
                    version: '3.4'
         | 
| 76 | 
            +
              type: :runtime
         | 
| 77 | 
            +
              prerelease: false
         | 
| 78 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 79 | 
            +
                requirements:
         | 
| 80 | 
            +
                - - "~>"
         | 
| 81 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 82 | 
            +
                    version: '3.4'
         | 
| 83 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 84 | 
            +
              name: etcher
         | 
| 85 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 | 
            +
                requirements:
         | 
| 87 | 
            +
                - - "~>"
         | 
| 88 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            +
                    version: '1.6'
         | 
| 90 | 
            +
              type: :runtime
         | 
| 91 | 
            +
              prerelease: false
         | 
| 92 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 93 | 
            +
                requirements:
         | 
| 94 | 
            +
                - - "~>"
         | 
| 95 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            +
                    version: '1.6'
         | 
| 97 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 98 | 
            +
              name: git
         | 
| 99 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 100 | 
            +
                requirements:
         | 
| 101 | 
            +
                - - "~>"
         | 
| 102 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 103 | 
            +
                    version: 2.1.1
         | 
| 104 | 
            +
              type: :runtime
         | 
| 105 | 
            +
              prerelease: false
         | 
| 106 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 107 | 
            +
                requirements:
         | 
| 108 | 
            +
                - - "~>"
         | 
| 109 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 110 | 
            +
                    version: 2.1.1
         | 
| 111 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 112 | 
            +
              name: infusible
         | 
| 113 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 114 | 
            +
                requirements:
         | 
| 115 | 
            +
                - - "~>"
         | 
| 116 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 117 | 
            +
                    version: '3.5'
         | 
| 118 | 
            +
              type: :runtime
         | 
| 119 | 
            +
              prerelease: false
         | 
| 120 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 121 | 
            +
                requirements:
         | 
| 122 | 
            +
                - - "~>"
         | 
| 123 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 124 | 
            +
                    version: '3.5'
         | 
| 125 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 126 | 
            +
              name: ruby-next-core
         | 
| 127 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 128 | 
            +
                requirements:
         | 
| 129 | 
            +
                - - "~>"
         | 
| 130 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 131 | 
            +
                    version: '1.0'
         | 
| 132 | 
            +
              type: :runtime
         | 
| 133 | 
            +
              prerelease: false
         | 
| 134 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 135 | 
            +
                requirements:
         | 
| 136 | 
            +
                - - "~>"
         | 
| 137 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 138 | 
            +
                    version: '1.0'
         | 
| 139 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 140 | 
            +
              name: runcom
         | 
| 141 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 142 | 
            +
                requirements:
         | 
| 143 | 
            +
                - - "~>"
         | 
| 144 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 145 | 
            +
                    version: '11.0'
         | 
| 146 | 
            +
              type: :runtime
         | 
| 147 | 
            +
              prerelease: false
         | 
| 148 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 149 | 
            +
                requirements:
         | 
| 150 | 
            +
                - - "~>"
         | 
| 151 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 152 | 
            +
                    version: '11.0'
         | 
| 153 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 154 | 
            +
              name: sod
         | 
| 155 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 156 | 
            +
                requirements:
         | 
| 157 | 
            +
                - - "~>"
         | 
| 158 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 159 | 
            +
                    version: '0.8'
         | 
| 160 | 
            +
              type: :runtime
         | 
| 161 | 
            +
              prerelease: false
         | 
| 162 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 163 | 
            +
                requirements:
         | 
| 164 | 
            +
                - - "~>"
         | 
| 165 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 166 | 
            +
                    version: '0.8'
         | 
| 167 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 168 | 
            +
              name: spek
         | 
| 169 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 170 | 
            +
                requirements:
         | 
| 171 | 
            +
                - - "~>"
         | 
| 172 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 173 | 
            +
                    version: '3.0'
         | 
| 174 | 
            +
              type: :runtime
         | 
| 175 | 
            +
              prerelease: false
         | 
| 176 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 177 | 
            +
                requirements:
         | 
| 178 | 
            +
                - - "~>"
         | 
| 179 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 180 | 
            +
                    version: '3.0'
         | 
| 181 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 182 | 
            +
              name: tty-file
         | 
| 183 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 184 | 
            +
                requirements:
         | 
| 185 | 
            +
                - - "~>"
         | 
| 186 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 187 | 
            +
                    version: '0.10'
         | 
| 188 | 
            +
              type: :runtime
         | 
| 189 | 
            +
              prerelease: false
         | 
| 190 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 191 | 
            +
                requirements:
         | 
| 192 | 
            +
                - - "~>"
         | 
| 193 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 194 | 
            +
                    version: '0.10'
         | 
| 195 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 196 | 
            +
              name: tty-pager
         | 
| 197 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 198 | 
            +
                requirements:
         | 
| 199 | 
            +
                - - "~>"
         | 
| 200 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 201 | 
            +
                    version: '0.14'
         | 
| 202 | 
            +
              type: :runtime
         | 
| 203 | 
            +
              prerelease: false
         | 
| 204 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 205 | 
            +
                requirements:
         | 
| 206 | 
            +
                - - "~>"
         | 
| 207 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 208 | 
            +
                    version: '0.14'
         | 
| 209 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 210 | 
            +
              name: zeitwerk
         | 
| 211 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 212 | 
            +
                requirements:
         | 
| 213 | 
            +
                - - "~>"
         | 
| 214 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 215 | 
            +
                    version: '2.6'
         | 
| 216 | 
            +
              type: :runtime
         | 
| 217 | 
            +
              prerelease: false
         | 
| 218 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 219 | 
            +
                requirements:
         | 
| 220 | 
            +
                - - "~>"
         | 
| 221 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 222 | 
            +
                    version: '2.6'
         | 
| 223 | 
            +
            description:
         | 
| 224 | 
            +
            email:
         | 
| 225 | 
            +
            - stex@stex.codes
         | 
| 226 | 
            +
            executables:
         | 
| 227 | 
            +
            - label_weaver
         | 
| 228 | 
            +
            extensions: []
         | 
| 229 | 
            +
            extra_rdoc_files:
         | 
| 230 | 
            +
            - README.md
         | 
| 231 | 
            +
            files:
         | 
| 232 | 
            +
            - README.md
         | 
| 233 | 
            +
            - exe/label_weaver
         | 
| 234 | 
            +
            - label_weaver.gemspec
         | 
| 235 | 
            +
            - lib/label_weaver.rb
         | 
| 236 | 
            +
            - lib/label_weaver/cli/actions/develop/start.rb
         | 
| 237 | 
            +
            - lib/label_weaver/cli/actions/develop/stop.rb
         | 
| 238 | 
            +
            - lib/label_weaver/cli/actions/diff/file.rb
         | 
| 239 | 
            +
            - lib/label_weaver/cli/actions/diff/format.rb
         | 
| 240 | 
            +
            - lib/label_weaver/cli/actions/init.rb
         | 
| 241 | 
            +
            - lib/label_weaver/cli/actions/prepare_base_project.rb
         | 
| 242 | 
            +
            - lib/label_weaver/cli/commands/develop.rb
         | 
| 243 | 
            +
            - lib/label_weaver/cli/commands/diff.rb
         | 
| 244 | 
            +
            - lib/label_weaver/cli/shell.rb
         | 
| 245 | 
            +
            - lib/label_weaver/configuration/contract.rb
         | 
| 246 | 
            +
            - lib/label_weaver/configuration/defaults.yml
         | 
| 247 | 
            +
            - lib/label_weaver/configuration/model.rb
         | 
| 248 | 
            +
            - lib/label_weaver/container.rb
         | 
| 249 | 
            +
            - lib/label_weaver/import.rb
         | 
| 250 | 
            +
            - lib/label_weaver/temp_repo.rb
         | 
| 251 | 
            +
            homepage: https://gitlab.com/lopo-tech/label_weaver
         | 
| 252 | 
            +
            licenses:
         | 
| 253 | 
            +
            - MIT
         | 
| 254 | 
            +
            metadata:
         | 
| 255 | 
            +
              label: LabelWeaver
         | 
| 256 | 
            +
              rubygems_mfa_required: 'true'
         | 
| 257 | 
            +
            post_install_message:
         | 
| 258 | 
            +
            rdoc_options: []
         | 
| 259 | 
            +
            require_paths:
         | 
| 260 | 
            +
            - lib
         | 
| 261 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 262 | 
            +
              requirements:
         | 
| 263 | 
            +
              - - "~>"
         | 
| 264 | 
            +
                - !ruby/object:Gem::Version
         | 
| 265 | 
            +
                  version: '3.3'
         | 
| 266 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 267 | 
            +
              requirements:
         | 
| 268 | 
            +
              - - ">="
         | 
| 269 | 
            +
                - !ruby/object:Gem::Version
         | 
| 270 | 
            +
                  version: '0'
         | 
| 271 | 
            +
            requirements: []
         | 
| 272 | 
            +
            rubygems_version: 3.5.14
         | 
| 273 | 
            +
            signing_key:
         | 
| 274 | 
            +
            specification_version: 4
         | 
| 275 | 
            +
            summary: Helper tool to manage whitelabel version of base projects
         | 
| 276 | 
            +
            test_files: []
         |