everything related to duct tape audio suite (dtas)
 help / color / mirror / Atom feed
From: Eric Wong <e@80x24.org>
To: dtas-all@nongnu.org
Subject: [PATCH 2/1] dtas-mlib: add dump support for debugging
Date: Sat, 28 Nov 2015 11:16:25 +0000
Message-ID: <20151128111625.GA21697@dcvr.yhbt.net> (raw)
In-Reply-To: <20151127115054.16912-1-e@80x24.org>

Using an RFC-822-like format since YAML quoting rules aren't very
human-friendly, and we already prevent newlines from entering our
DB anyways.
---
 bin/dtas-mlib    |  18 +++++---
 lib/dtas/mlib.rb | 134 +++++++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 132 insertions(+), 20 deletions(-)

diff --git a/bin/dtas-mlib b/bin/dtas-mlib
index 0e17d91..6331808 100755
--- a/bin/dtas-mlib
+++ b/bin/dtas-mlib
@@ -1,7 +1,7 @@
 #!/usr/bin/env ruby
 # Copyright (C) 2015 all contributors <dtas-all@nongnu.org>
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
-usage = "#$0 [-d DATABASE-URI] ACTION [DIRECTORY]"
+usage = "#$0 [-d DATABASE-URI] ACTION [ARGS]"
 Thread.abort_on_exception = $stderr.sync = $stdout.sync = true
 require 'dtas/mlib'
 require 'optparse'
@@ -27,13 +27,19 @@ unless db.include?('://')
   end
 end
 
+def mlib(db, migrate: false)
+  m = DTAS::Mlib.new(db)
+  m.migrate if migrate
+  m
+end
+
 case action = ARGV.shift
-when 'update'
+when 'update', 'up'
   directory = ARGV.shift or abort "DIRECTORY required\n#{usage}"
+  mlib(db, migrate: true).update(directory)
+when 'dump' # mainly for debugging
+  directory = ARGV.shift || '/'
+  mlib(db).dump(directory)
 else
   abort usage
 end
-
-mlib = DTAS::Mlib.new(db)
-mlib.migrate
-mlib.__send__(action, directory)
diff --git a/lib/dtas/mlib.rb b/lib/dtas/mlib.rb
index 59a589c..9a112c9 100644
--- a/lib/dtas/mlib.rb
+++ b/lib/dtas/mlib.rb
@@ -11,6 +11,7 @@ class DTAS::Mlib
   attr_accessor :follow_outside_symlinks
   attr_accessor :follow_inside_symlinks
   attr_accessor :tags
+
   DM_DIR = -1
   DM_IGN = -2
   include DTAS::Process
@@ -240,6 +241,10 @@ class DTAS::Mlib
     node[:id] = node_id
   end
 
+  def node_lookup(parent_id, name)
+    @db[:nodes][name: name, parent_id: parent_id]
+  end
+
   def node_ensure(parent_id, name, tlen, ctime = nil)
     q = { name: name, parent_id: parent_id }
     if node = @db[:nodes][q]
@@ -254,28 +259,33 @@ class DTAS::Mlib
     node
   end
 
-  def scan_dir(path, st, parent_id = nil)
+  def cd(path)
     prev_wd = @pwd
     Dir.chdir(path)
     cur = @pwd = Dir.pwd.b
-
-    # TODO: use parent_id if given
-    dir = dir_vivify(cur.split(%r{/+}n), st.ctime.to_i)
-    Dir.foreach('.', encoding: Encoding::BINARY) do |x|
-      case x
-      when '.', '..', %r{\n}n
-        # files with newlines in them are rare and last I checked (in 2008),
-        # mpd could not support them, either.  So lets not bother for now.
-        next
-      else
-        scan_any(x, dir[:id])
-      end
-    end
+    yield
   ensure
     Dir.chdir(prev_wd) if cur && prev_wd
     @pwd = prev_wd
   end
 
+  def scan_dir(path, st, parent_id = nil)
+    cd(path) do
+      # TODO: use parent_id if given
+      dir = dir_vivify(@pwd.split(%r{/+}n), st.ctime.to_i)
+      Dir.foreach('.', encoding: Encoding::BINARY) do |x|
+        case x
+        when '.', '..', %r{\n}n
+          # files with newlines in them are rare and last I checked (in 2008),
+          # mpd could not support them, either.  So lets not bother for now.
+          next
+        else
+          scan_any(x, dir[:id])
+        end
+      end
+    end
+  end
+
   def send_harder(sock, msg)
     sock.sendmsg(msg)
   rescue Errno::EMSGSIZE
@@ -287,4 +297,100 @@ class DTAS::Mlib
       warn "#{msg.bytesize} too big, dropped #{e.class}"
     end
   end
+
+  def find_dump_part(cur, base)
+    parts = @pwd.split(%r{/+}n)
+    parts.shift # no first part
+    parts << base if base
+    parts.each do |name|
+      if cur = node_lookup(cur[:id], name)
+        case cur[:tlen]
+        when DM_DIR then next # keep going
+        when DM_IGN then return [ :ignored, cur ]
+        else # regular audio
+          return cur if name.object_id == parts[-1].object_id
+          return [ :notdir, cur ]
+        end
+      else
+        return [ :missing, name ]
+      end
+    end
+    cur
+  end
+
+  # returns an array on error
+  def dump(path)
+    dir = path
+    base = nil
+    retried = false
+    begin
+      found = cd(dir) { find_dump_part(root_node, base) }
+    rescue Errno::ENOTDIR
+      raise if retried || found
+      dir, base = File.split(path)
+      retried = true
+      retry
+    end
+    return found if Array === found # error
+
+    # success
+    load_tags
+    require 'yaml'
+    @tag_rmap = @tag_map.invert
+    if found[:tlen] == DM_DIR
+      emit_recurse(found)
+    else
+      parent = @db[:nodes][id: found[:parent_id]]
+      parent or abort "missing parent for #{found.inspect}"
+      parent[:dirname] ||= path_of(parent)
+      emit_1(found, parent)
+    end
+  end
+
+  def path_of(node)
+    return '/' if node[:name] == ''
+    parts = [ node[:name], '' ]
+    begin
+      node = @db[:nodes][id: node[:parent_id]]
+      break if node[:id] == node[:parent_id]
+      parts.unshift node[:name]
+    end while true
+    parts.unshift('')
+    parts.join('/')
+  end
+
+  def emit_recurse(node)
+    node[:dirname] ||= path_of(node)
+    @db[:nodes].where(parent_id: node[:id]).order(:name).each do |nd|
+      next if nd[:id] == node[:id] # root_node
+      case nd[:tlen]
+      when DM_DIR then emit_recurse(nd)
+      when DM_IGN then next
+      else
+        emit_1(nd, node)
+      end
+    end
+  end
+
+  def emit_1(node, parent)
+    comments = Hash.new { |h,k| h[k] = [] }
+    @db['SELECT c.tag_id, v.val FROM comments c ' \
+        'LEFT JOIN vals v ON v.id = c.val_id ' \
+        "WHERE c.node_id = #{node[:id]} ORDER BY c.tag_id"].map do |c|
+      comments[@tag_rmap[c[:tag_id]]] << c[:val]
+    end
+    puts "Path: #{parent[:dirname]}#{node[:name]}"
+    puts "Length: #{node[:tlen]}"
+    return if comments.empty?
+    puts 'Comments:'
+    comments.each do |k,v|
+      if v.size == 1
+        puts "\t#{k}: #{v[0]}"
+      else
+        v << ''
+        puts "\t#{k}:\n\t\t#{v.join("\t\t\n")}"
+      end
+    end
+    puts
+  end
 end
-- 
EW



      reply	other threads:[~2015-11-28 11:16 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-27 11:50 [PATCH] introduce dtas-mlib for music library functions Eric Wong
2015-11-28 11:16 ` Eric Wong [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://80x24.org/dtas/README

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20151128111625.GA21697@dcvr.yhbt.net \
    --to=e@80x24.org \
    --cc=dtas-all@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

everything related to duct tape audio suite (dtas)

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://80x24.org/dtas-all
	git clone --mirror http://ou63pmih66umazou.onion/dtas-all

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V1 dtas-all dtas-all/ https://80x24.org/dtas-all \
		dtas-all@nongnu.org
	public-inbox-index dtas-all

Example config snippet for mirrors.
Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.audio.dtas
	nntp://ou63pmih66umazou.onion/inbox.comp.audio.dtas
 note: .onion URLs require Tor: https://www.torproject.org/

code repositories for the project(s) associated with this inbox:

	../../dtas.git

AGPL code for this site: git clone http://ou63pmih66umazou.onion/public-inbox.git