※当サイトの記事には、広告・プロモーションが含まれます。

Oxidized内部で利用されてるRuggedというライブラリがややこしくしてくれている話

gigazine.net

音楽には気分を高めたり、穏やかな睡眠へといざなったりする効果があるため、日常生活の中でよく音楽を聴くという人は多いはず。医療現場でも、音楽を通じて認知症や記憶障害のある高齢者の認知機能を改善させる音楽療法が行われているとのことで、そのメカニズムや効果について専門家が論じました。

音楽には脳細胞を修復し認知症の進行を遅らせる力がある - GIGAZINE

イギリスのアングリア・ラスキン大学で音楽療法を研究しているミン・フン・シュー氏とレベッカアトキンソン氏によると、どんな音楽でも脳を再生させてくれるわけではないとのこと。

音楽には脳細胞を修復し認知症の進行を遅らせる力がある - GIGAZINE

聴く人の気分に最も大きな影響を与えるのは、なじみのあるお気に入りの曲で、これは好きな音楽を聴くと快感を与えるホルモンが分泌されることに由来しています。

音楽には脳細胞を修復し認知症の進行を遅らせる力がある - GIGAZINE

⇧『NO MUSIC, NO LIFE』、『音楽は国境を越える』などなど、音楽に関するキャッチーな言葉は多いですが、楽しむことができるのであれば音楽以外でも良いような気はしますな。

結局のところ、ストレスが一番、人に害を与える気がしますしな。

Oxidizedとは

GitHubで公開されているREADMEによると、

github.com

Oxidized is a network device configuration backup tool. It's a RANCID replacement!

It is light and extensible and supports over 130 operating system types.

https://github.com/ytti/oxidized

⇧ ネットワーク機器の設定情報をバックアップすることを目的としたライブラリですと。

実装はというと、

⇧ ほぼ、Ruby

Ruggedとは

GitHubで公開されているREADMEによると、

github.com

libgit2 bindings in Ruby

Rugged is a library for accessing libgit2 in Ruby. It gives you the speed and portability of libgit2 with the beauty of the Ruby language.

https://github.com/libgit2/rugged

⇧「libgit2」というライブラリをRubyから利用できるようにしたものらしい。

「libgit2」はというと、

libgit2

libgit2 is a pure C implementation of the Git core methods. It's designed to be fast and portable. For more information about libgit2, check out libgit2's website or browse the libgit2 organization on GitHub.

https://github.com/libgit2/rugged

C言語でできてると...

github.com

libgit2 is a portable, pure C implementation of the Git core methods provided as a linkable library with a solid API, allowing to build Git functionality into your application.

https://github.com/libgit2/libgit2

libgit2 is used in a variety of places, from GUI clients to hosting providers ("forges") and countless utilities and applications in between. Because it's written in C, it can be made available to any other programming language through "bindings", so you can use it in Ruby.NETPythonNode.jsRust, and more.

https://github.com/libgit2/libgit2

⇧ Git操作に関するAPIが用意されているそうな。

Gitのbare repositoryとnon-bare repository

Git本家のドキュメントによると、

git-scm.com

In order to initially set up any Git server, you have to export an existing repository into a new bare repository — a repository that doesn’t contain a working directory.

https://git-scm.com/book/en/v2/Git-on-the-Server-Getting-Git-on-a-Server

⇧ うむ、「working directory」が何なのかの説明が無いのだが、

⇧ とあることから、「.git」ディレクトリ以外が「working directory」という認識で良いんかね?

海外でも「working directory」の正確な定義が分からんとの声が上がっておりますな。

stackoverflow.com

stackoverflow.com

tutorialhorizon.com

⇧ 何となく、「.git」ディレクトリ以外を「workig directory」と見なせば良いんかね?

「.git」ディレクトリはというと、

www.geeksforgeeks.org

⇧ 上図のような感じで、情報を管理してるっぽい。

git commitされたようなファイルの実体は、

github.blog

⇧ 上記のような感じで、「.git/objects」ディレクトリで管理されるらしい。

2024年10月19日(土)追記:↓ ここから

公式のドキュメントの「git clone」の説明によると、

git-scm.com

⇧ とあり、「bare repository」は、「.git」ディレクトリの中身だけがあるディレクトリが用意されるのであって、「.git」ディレクトリは存在しないと。

ただ、

git-scm.com

環境変数「GIT_DIR」の扱いがどうなるんだろうか...

「bare repository」は、「.git」ディレクトリが存在しない形になるからして、『GIT_DIR は .git フォルダの場所です。 指定されていない場合、Gitはディレクトリツリーを ~ または / にたどり着くまで上っていき、各ディレクトリで .git ディレクトリを探します。

という説明だけだと、「bare repository」は「.git」ディレクトリが無いわけだから、「bare repository」の場合「リポジトリの場所」はどう確認すれば良いのか分からないんだが...

オプションが多過ぎて理解が追い付かないのだが、

www.omnibuscode.com

⇧ 少なくとも、4つのGit リポジトリの構成があるみたい。

とりあえず、

  • bare
  • non-bare
    • normal
    • no-checkout
    • mirror

⇧ のような区別を付けるとして、我々になじみの深いのは、「normal」の形になるような気がしている。

2024年10月19日(土)追記:↑ ここまで

Oxidized内部で利用されてるRuggedというライブラリがややこしくしてくれている話

で、「Rugged」というライブラリですが、

kinoppyd.dev

⇧上記サイト様で説明のあるように、通常のGitコマンドと異なり、直接、「.git」ディレクトリに対して変更を反映してくれてしまうと。

つまり、ローカル側にファイルが残らないのである。

で、「Oxidized」のソースコードを見ると、

github.com

https://github.com/ytti/oxidized/blob/master/lib/oxidized/output/git.rb

module Oxidized
  class Git < Output
    using Refinements

    class GitError < OxidizedError; end
    begin
      require 'rugged'
    rescue LoadError
      raise OxidizedError, 'rugged not found: sudo gem install rugged'
    end

    attr_reader :commitref

    def initialize
      super
      @cfg = Oxidized.config.output.git
    end

    def setup
      if @cfg.empty?
        Oxidized.asetus.user.output.git.user  = 'Oxidized'
        Oxidized.asetus.user.output.git.email = 'o@example.com'
        Oxidized.asetus.user.output.git.repo = File.join(Config::ROOT, 'oxidized.git')
        Oxidized.asetus.save :user
        raise NoConfig, "no output git config, edit #{Oxidized::Config.configfile}"
      end

      if @cfg.repo.respond_to?(:each)
        @cfg.repo.each do |group, repo|
          @cfg.repo["#{group}="] = File.expand_path repo
        end
      else
        @cfg.repo = File.expand_path @cfg.repo
      end
    end

    def store(file, outputs, opt = {})
      @msg   = opt[:msg]
      @user  = opt[:user]  || @cfg.user
      @email = opt[:email] || @cfg.email
      @opt   = opt
      @commitref = nil
      repo = @cfg.repo

      outputs.types.each do |type|
        type_cfg = ''
        type_repo = File.join(File.dirname(repo), type + '.git')
        outputs.type(type).each do |output|
          (type_cfg << output; next) unless output.name # rubocop:disable Style/Semicolon
          type_file = file + '--' + output.name
          if @cfg.type_as_directory?
            type_file = type + '/' + type_file
            type_repo = repo
          end
          update type_repo, type_file, output
        end
        update type_repo, file, type_cfg
      end

      update repo, file, outputs.to_cfg
    end

    def fetch(node, group)
      repo, path = yield_repo_and_path(node, group)
      repo = Rugged::Repository.new repo
      index = repo.index
      index.read_tree repo.head.target.tree unless repo.empty?
      repo.read(index.get(path)[:oid]).data
    rescue StandardError
      'node not found'
    end

    # give a hash of all oid revision for the given node, and the date of the commit
    def version(node, group)
      repo, path = yield_repo_and_path(node, group)

      repo = Rugged::Repository.new repo
      walker = Rugged::Walker.new(repo)
      walker.sorting(Rugged::SORT_DATE)
      walker.push(repo.head.target.oid)
      i = -1
      tab = []
      walker.each do |commit|
        # Diabled rubocop because the suggested .empty? does not work here.
        next if commit.diff(paths: [path]).size.zero? # rubocop:disable Style/ZeroLengthPredicate

        hash = {}
        hash[:date] = commit.time.to_s
        hash[:oid] = commit.oid
        hash[:author] = commit.author
        hash[:message] = commit.message
        tab[i += 1] = hash
      end
      walker.reset
      tab
    rescue StandardError
      'node not found'
    end

    # give the blob of a specific revision
    def get_version(node, group, oid)
      repo, path = yield_repo_and_path(node, group)
      repo = Rugged::Repository.new repo
      repo.blob_at(oid, path).content
    rescue StandardError
      'version not found'
    end

    # give a hash with the patch of a diff between 2 revision and the stats (added and deleted lines)
    def get_diff(node, group, oid1, oid2)
      diff_commits = nil
      repo, = yield_repo_and_path(node, group)
      repo = Rugged::Repository.new repo
      commit = repo.lookup(oid1)

      if oid2
        commit_old = repo.lookup(oid2)
        diff = repo.diff(commit_old, commit)
        diff.each do |patch|
          if /#{node.name}\s+/ =~ patch.to_s.lines.first
            diff_commits = { patch: patch.to_s, stat: patch.stat }
            break
          end
        end
      else
        stat = commit.parents[0].diff(commit).stat
        stat = [stat[1], stat[2]]
        patch = commit.parents[0].diff(commit).patch
        diff_commits = { patch: patch, stat: stat }
      end

      diff_commits
    rescue StandardError
      'no diffs'
    end

    private

    def yield_repo_and_path(node, group)
      repo, path = node.repo, node.name

      path = "#{group}/#{node.name}" if group && !group.empty? && @cfg.single_repo?

      [repo, path]
    end

    def update(repo, file, data)
      return if data.empty?

      if @opt[:group]
        if @cfg.single_repo?
          file = File.join @opt[:group], file
        else
          repo = if repo.is_a?(::String)
                   File.join File.dirname(repo), @opt[:group] + '.git'
                 else
                   repo[@opt[:group]]
                 end
        end
      end

      begin
        repo = Rugged::Repository.new repo
        update_repo repo, file, data
      rescue Rugged::OSError, Rugged::RepositoryError => e
        begin
          Rugged::Repository.init_at repo, :bare
        rescue StandardError => create_error
          raise GitError, "first '#{e.message}' was raised while opening git repo, then '#{create_error.message}' was while trying to create git repo"
        end
        retry
      end
    end

    def update_repo(repo, file, data)
      oid_old = repo.blob_at(repo.head.target_id, file) rescue nil
      return false if oid_old && (oid_old.content.b == data.b)

      oid = repo.write data, :blob
      index = repo.index
      index.add path: file, oid: oid, mode: 0o100644

      repo.config['user.name']  = @user
      repo.config['user.email'] = @email
      @commitref = Rugged::Commit.create(repo,
                                         tree:       index.write_tree(repo),
                                         message:    @msg,
                                         parents:    repo.empty? ? [] : [repo.head.target].compact,
                                         update_ref: 'HEAD')

      index.write
      true
    end
  end
end    

⇧ という感じで、「Rugged」を利用してくれてしまっているわけで、

git commit    

⇧「git commit」相当なところまで、実施してくれちゃうのだが、どういうわけか、「branch」が「master」で処理してくれちゃうのですな...

zenn.dev

特に問題ではないのですが、Oxidizedのこちらのリポ機能はGithub用に作られているみたいで、デフォのリポ名がMasterになっています。
GitlabはデフォがMainになりますので、事前にGitlab側ですり替えておくか、Oxidizedの設定で変更する必要があります。(今回の例ではGitlab側で変更してます。)

OxidizedによるGitlabへのコンフィグバックアップ

⇧ とあるのだけど、

github.blog

GitHubも2020年8月1日に、「branch」は「main」になりますって言ってるのよね...

とりあえず、「Oxidized」の「Rugged」の利用の仕方がイケていないのであって、「Rugged」のせいでは無いらしい。

話を元に戻して、何が言いたいかというと、

git push origin main    

⇧ のようなことはエラーになってしまうわけだ。

何故ならば、「Oxidized」の実装が、「branch」を「master」固定で処理する形になってしまっているため。

envader.plus

⇧ 上記サイト様にあるような、「ローカル」と「リモート」の「branch」の指定の際に、異なる「branch」を指定できるのかは分からないが、兎に角、「Oxidized」は「変更容易性」が残念な感じではある...

そもそも、「branch」を指定できるような作りにしなかったのは何故なのか...

ちなみに、

zenn.dev

⇧ 上記サイト様によりますと、

git push origin main    

⇧ はイケてないらしく、

git push origin HEAD    

⇧ のようにするのが良いみたい。

ウッカリ、作業してる「branch」を変更してたりした場合にダメージが大きそうではあるが...

毎度モヤモヤ感が半端ない…

今回はこのへんで。