monotone-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Monotone-devel] [PATCH] mtn attr mass_set ; pick up attributes from fil


From: Daniel Dickinson
Subject: [Monotone-devel] [PATCH] mtn attr mass_set ; pick up attributes from filesystem in one go
Date: Thu, 17 Aug 2006 02:19:42 -0400

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Okay, I finally got the attr mass_set command working.  It allows
you to update the attributes recorded on monotone for files tracked
by monotone to the current settings on filesystem.  I've created the
patch against 0.28 because I was having problems with the latest head.

# 
# old_revision [8c6ce7cb2ccd21290b435e042c2be4554ec6a048]
# 
# add_file "examples/mtn-dosh"
#  content [4b27481a2dc207c901c0acbbf761d5d26d2fdc69]
# 
# add_file "examples/unix_attributes.lua"
#  content [b4b0797b13a7923e7e1f71285551d17adc142336]
# 
# patch "cmd_ws_commit.cc"
#  from [f24529cd245deb0002fdaa15f0f8b6d1e9d0e338]
#    to [562517ec4d18604fd4a5e211aeb78895d131c196]
# 
# patch "lua_hooks.cc"
#  from [0650e44236b780eca2e9bd964b303d08291a5a68]
#    to [e3b7f945cbb1eafe5a1ae172926a600622d54db5]
# 
# patch "lua_hooks.hh"
#  from [f7acc9339fb54e2093797b8c7192b6846d7b6fe5]
#    to [a7552e1c059eb98b54299255eb9d810108ad2afc]
# 
# patch "roster.cc"
#  from [3773a5236971e2912de250e1c76757b1c5e0cdbc]
#    to [1ae5df20aa4213f621febefdab136d47db09d603]
# 
# patch "roster.hh"
#  from [49ce9f36b5f507091d99d4889e04fd231275029c]
#    to [dd199b8cacb11703aa559df819dbcac1fa3c7f0e]
# 
# patch "std_hooks.lua"
#  from [b49b50671ccf60eca56f16f7333eaf6c4b79465c]
#    to [0526c17008c70e3432791e9125ba781aaa839057]
# 
# patch "work.cc"
#  from [02f33f9a20217a5ceaf213e892e66a41a2780441]
#    to [99ee8ae1f14fd0212d72cf853b4e2efcb02c938e]
# 
# patch "work.hh"
#  from [7634d8afc541e4a1ddc3e770b033e058338601de]
#    to [0229f6f68b577fcb30bcb0f1084d1bd500c9052f]
# 
#   set "examples/mtn-dosh"
#  attr "group"
# value "1001"
# 
#   set "examples/mtn-dosh"
#  attr "perms"
# value "664"
# 
#   set "examples/mtn-dosh"
#  attr "user"
# value "1001"
# 
#   set "examples/unix_attributes.lua"
#  attr "group"
# value "1001"
# 
#   set "examples/unix_attributes.lua"
#  attr "perms"
# value "664"
# 
#   set "examples/unix_attributes.lua"
#  attr "user"
# value "1001"
# 
============================================================
- --- examples/mtn-dosh 4b27481a2dc207c901c0acbbf761d5d26d2fdc69
+++ examples/mtn-dosh   4b27481a2dc207c901c0acbbf761d5d26d2fdc69
@@ -0,0 +1,4 @@
+#!/bin/sh
+TMPFILE=$1
+shift
+$1 $2 $3 $4 $5 $6 $7 $8 $9 > $TMPFILE
============================================================
- --- examples/unix_attributes.lua
b4b0797b13a7923e7e1f71285551d17adc142336 +++
examples/unix_attributes.lua
b4b0797b13a7923e7e1f71285551d17adc142336 @@ -0,0 +1,161 @@ +function
getdbgval()
+    return 0
+end
+
+if (attr_update_functions == nil) then
+    attr_update_functions = {}
+end
+
+function argstr(...)
+    local argstr = ""
+    for i,v in ipairs(arg) do
+        if (argstr ~= "") then
+            argstr = argstr .. ' '
+        end
+        argstr = argstr .. tostring(v) 
+    end
+    if (getdbgval() > 3) then print("Argument string is: " .. argstr)
end
+    return argstr
+end
+
+function execute_redirout(tmpfilename, command, ...)
+    return execute('mtn-dosh', tmpfilename, command, unpack(arg)) 
+end
+         
+function execute_out(command, ...)
+    local out = nil
+    local exec_retval
+    local outhnd
+    local errstr
+    local out
+    local tmpfile, tmpfilename = temp_file()
+    tmpfile:close()
+    exec_retval = execute_redirout(tmpfilename, command, unpack(arg))
+    if (exec_retval == 0) then
+       outhnd, errstr = io.open(tmpfilename)
+       if (outhnd) then
+           out, errstr = outhnd:read("*line") 
+           if (out == nil) then
+               if (getdbgval() > 1) then
+                   if (errstr) then
+                       print("Error reading " .. tmpfilename .. ":
" .. errstr)
+                   else
+                       print("Error reading " .. tmpfilename .. ":
" .. 'nil')
+                   end
+               end
+           end
+           outhnd:close()
+          os.remove(tmpfilename)
+      else
+          if (getdbgval() > 1) then
+              if (errstr) then
+                  print("Error opening " .. tmpfilename .. ": " ..
errstr)
+              else
+                  print("Error opening " .. tmpfilename .. ": " ..
'nil')
+              end
+          end
+          os.remove(tmpfilename)
+       end 
+    else
+        print('Error executing ' .. 'mtn-dosh ' .. command ..
argstr(unpack(arg)) .. ' > ' .. tmpfilename .. ': ' ..
tostring(exec_retval))
+       os.remove(tmpfilename)
+    end
+ 
+    if (getdbgval() > 1) then
+        if (out ~= nil) then
+            print('execute_redirout; got ' .. out)
+        else
+            print('no output')
+        end
+    end
+    return out
+end
+
+function is_symlink(filename)
+    local filetype = execute_out('stat', '-c', '%F', filename)
+    local link_target 
+    local retlink = nil
+    if (filetype == "symbolic link") then
+       link_target = execute_out('readlink', filename)
+        if (link_target) then
+            if (link_target ~= "" ) then
+                retlink = link_target
+            end
+        end
+    end
+    if ((getdbgval() > 2) and retlink) then
+       print("linktarget = " .. retlink)
+    end
+    return retlink
+end
+   
+attr_init_functions["perms"] = function(filename)
+    return execute_out('stat', '-c', '%a', filename)
+end
+
+attr_init_functions["user"] = function(filename)
+    return execute_out('stat', '-c', '%u', filename) 
+end
+
+attr_init_functions["group"] = function(filename)
+    return execute_out('stat', '-c', '%g', filename) 
+end
+
+attr_init_functions["symlink"] = function(filename)
+    return is_symlink(filename)
+end
+
+attr_update_functions["perms"] = function(filename, value)
+    return execute_out('stat', '-c', '%a', filename)
+end
+
+attr_update_functions["user"] = function(filename, value)
+    return execute_out('stat', '-c', '%u', filename) 
+end
+
+attr_update_functions["group"] = function(filename, value)
+    return execute_out('stat', '-c', '%g', filename) 
+end
+
+attr_update_functions["symlink"] = function(filename, value)
+    return is_symlink(filename)
+end
+
+attr_functions["perms"] = function(filename, value)
+    if (value ~= nil) then
+        execute("/bin/chmod", value, filename)
+    end
+end
+
+attr_functions["user"] = function(filename, value)
+    if (value ~= nil) then
+        execute("/bin/chown", value, filename)
+    end
+end
+
+attr_functions["group"] = function(filename, value)
+    if (value ~= nil) then
+        execute("/bin/chgrp", value, filename)
+    end
+end
+
+attr_functions["symlink"] = function(filename, value)
+    if (value ~= nil) then
+        execute("/bin/mv", filename, filename .. ".old")
+        if (execute("/bin/ln", "-s", value, filename) == 0) then
+            os.remove(filename .. ".old")
+        else
+            execute("/bin/cp", '-a', filename .. ".old", filename)
+        end
+    else
+        execute("/bin/mv", filename, filename .. ".old")
+        local realname = execute("/bin/readlink", filename)
+        if (realname ~= nil) then
+            if (execute("/bin/cp", '-a', realname, filename) == 0) then
+                os.remove(filename .. ".old")
+            else
+                execute("/bin/cp", '-a', filename .. ".old", filename)
+            end
+        end                        
+    end
+end
============================================================
- --- cmd_ws_commit.cc  f24529cd245deb0002fdaa15f0f8b6d1e9d0e338
+++ cmd_ws_commit.cc    562517ec4d18604fd4a5e211aeb78895d131c196
@@ -162,6 +162,8 @@ CMD(revert, N_("workspace"), N_("[PATH].
 
   // Race.
   put_work_cset(excluded);
+  // FIXME_ATTRS: All attributes are reverted, even if we specify
+  // path to revert
   update_any_attrs(app);
   maybe_update_inodeprints(app);
 }
@@ -519,38 +521,61 @@ ALIAS(co, checkout)
 
 ALIAS(co, checkout)
 
- -CMD(attr, N_("workspace"), N_("set PATH ATTR VALUE\nget PATH
[ATTR]\ndrop PATH [ATTR]"),
- -    N_("set, get or drop file attributes"),
+CMD(attr, N_("workspace"), N_("set PATH ATTR VALUE\nget PATH
[ATTR]\ndrop PATH [ATTR]\nmass_set [PATH...]"),
+    N_("set, get or drop file attributes\nor set recorded attributes
to match actual attributes on all\nfiles in PATH(s)."), OPT_NONE)
 {
- -  if (args.size() < 2 || args.size() > 4)
+  // FIXME_ATTRS:  General question; should attributes only be
modified on
+  // filesystem when --execute is specified?
+  
+  if (args.size() < 1)
     throw usage(name);
- -
- -  roster_t old_roster, new_roster;
- -  temp_node_id_source nis;
- -
- -  app.require_workspace();
- -  get_base_and_current_roster_shape(old_roster, new_roster, nis, app);
- -
- -
- -  file_path path = file_path_external(idx(args,1));
- -  split_path sp;
- -  path.split(sp);
- -
- -  N(new_roster.has_node(sp), F("Unknown path '%s'") % path);
- -  node_t node = new_roster.get_node(sp);
- -
+   
   string subcmd = idx(args, 0)();
- -  if (subcmd == "set" || subcmd == "drop")
+   
+  if (subcmd == "mass_set")
+     {
+       std::vector<file_path> paths;
+       
+       if (args.size() < 2)
+         {
+           paths = std::vector<file_path>();
+         }
+       else
+         {
+           std::vector<utf8>::const_iterator pbegin = args.begin();
+           ++pbegin;
+           for ( ; pbegin != args.end(); ++pbegin) 
+             {
+               paths.push_back(file_path_external(*pbegin));
+             }
+         }
+       
+       perform_attr_update(paths, app);        
+     }
+  else if (subcmd == "set" || subcmd == "drop")
     {
+      roster_t old_roster, new_roster;
+      temp_node_id_source nis;
+       
+      app.require_workspace();
+      get_base_and_current_roster_shape(old_roster, new_roster, nis,
app); 
+  
+      file_path path = file_path_external(idx(args,1));
+      split_path sp;
+      path.split(sp);
+        
+      N(new_roster.has_node(sp), F("Unknown path '%s'") % path);
+      node_t node = new_roster.get_node(sp);
+
       if (subcmd == "set")
         {
           if (args.size() != 4)
- -            throw usage(name);
- -
+              throw usage(name);
+          
           attr_key a_key = idx(args, 2)();
           attr_value a_value = idx(args, 3)();
- -
+            
           node->attrs[a_key] = make_pair(true, a_value);
         }
       else
@@ -581,6 +606,19 @@ CMD(attr, N_("workspace"), N_("set PATH 
     }
   else if (subcmd == "get")
     {
+      roster_t old_roster, new_roster;
+      temp_node_id_source nis;
+       
+      app.require_workspace();
+      get_base_and_current_roster_shape(old_roster, new_roster, nis,
app); 
+  
+      file_path path = file_path_external(idx(args,1));
+      split_path sp;
+      path.split(sp);
+        
+      N(new_roster.has_node(sp), F("Unknown path '%s'") % path);
+      node_t node = new_roster.get_node(sp);
+
       if (args.size() == 2)
         {
           bool has_any_live_attrs = false;
@@ -609,14 +647,12 @@ CMD(attr, N_("workspace"), N_("set PATH 
                      % a_key % path) << "\n";
         }
       else
- -        throw usage(name);
+        throw usage(name);  
     }
   else
     throw usage(name);
 }
 
- -
- -
 CMD(commit, N_("workspace"), N_("[PATH]..."),
     N_("commit workspace to database"),
     OPT_BRANCH_NAME % OPT_MESSAGE % OPT_MSGFILE % OPT_DATE %
============================================================
- --- lua_hooks.cc      0650e44236b780eca2e9bd964b303d08291a5a68
+++ lua_hooks.cc        e3b7f945cbb1eafe5a1ae172926a600622d54db5
@@ -684,6 +684,59 @@ bool
 }
 
 bool
+lua_hooks::hook_get_avail_attr_update_functions(std::vector<std::string>
& avail_funcs) +{
+  Lua ll(st);
+  string attr;
+
+  ll
+    .push_str("attr_update_functions")
+    .get_tab();
+
+  ll.begin();
+  while (ll.next())
+    {
+      ll.pop().extract_str(attr);
+      L(FL("avail attr_update '%s'") % attr);
+      avail_funcs.push_back(attr);
+    }
+  return ll.ok();
+}
+
+bool
+lua_hooks::hook_update_attribute(std::string const & inattr,
+                                 file_path const & filename,
+                                 std::string const & invalue,
+                                 std::string & outvalue)
+{
+  Lua ll(st);
+
+  ll
+    .push_str("attr_update_functions")
+    .get_tab()
+    .push_str(inattr)
+    .get_fn(-2)
+    .push_str(filename.as_external())
+    .push_str(invalue);
+
+  L(FL("calling an attr_update_function for attribute '%s' with value
'%s'") % inattr % invalue);  
+  ll.call(2,1);
+
+  string luakey, luavalue;
+
+  if (lua_isnil(st, -1))
+    {
+      outvalue = "";
+    }
+  else
+    {
+      ll.extract_str(outvalue);
+    }
+  
+  return ll.pop().ok();
+}
+
+bool
 lua_hooks::hook_init_attributes(file_path const & filename,
                                 map<string, string> & attrs)
 {
============================================================
- --- lua_hooks.hh      f7acc9339fb54e2093797b8c7192b6846d7b6fe5
+++ lua_hooks.hh        a7552e1c059eb98b54299255eb9d810108ad2afc
@@ -106,6 +106,14 @@ public:
   // attribute hooks
   bool hook_init_attributes(file_path const & filename,
                             std::map<std::string, std::string> &
attrs); +
+  bool hook_get_avail_attr_update_functions(std::vector<std::string> &
avail_funcs); +
+  bool hook_update_attribute(std::string const & inattr,
+                             file_path const & filename,
+                             std::string const & invalue,
+                             std::string & outvalue);
+
   bool hook_apply_attribute(std::string const & attr,
                             file_path const & filename,
                             std::string const & value);
============================================================
- --- roster.cc 3773a5236971e2912de250e1c76757b1c5e0cdbc
+++ roster.cc   1ae5df20aa4213f621febefdab136d47db09d603
@@ -2295,12 +2295,13 @@ update_current_roster_from_filesystem(ro
 void
 update_current_roster_from_filesystem(roster_t & ros,
                                       node_restriction const & mask,
- -                                      app_state & app)
+                                      app_state & app,
+                                      bool use_inodeprints_mode)
 {
   temp_node_id_source nis;
   inodeprint_map ipm;
 
- -  if (in_inodeprints_mode())
+  if (use_inodeprints_mode && in_inodeprints_mode())
     {
       data dat;
       read_inodeprints(dat);
============================================================
- --- roster.hh 49ce9f36b5f507091d99d4889e04fd231275029c
+++ roster.hh   dd199b8cacb11703aa559df819dbcac1fa3c7f0e
@@ -363,8 +363,10 @@ update_current_roster_from_filesystem(ro
 void
 update_current_roster_from_filesystem(roster_t & ros,
                                       node_restriction const & mask,
- -                                      app_state & app);
+                                      app_state & app,
+                                      bool use_inodeprints_mode =
true); 
+
 void
 update_current_roster_from_filesystem(roster_t & ros,
                                       app_state & app);
============================================================
- --- std_hooks.lua     b49b50671ccf60eca56f16f7333eaf6c4b79465c
+++ std_hooks.lua       0526c17008c70e3432791e9125ba781aaa839057
@@ -872,3 +872,8 @@ end
 function get_mtn_command(host)
         return "mtn"
 end
+
+if (attr_update_functions == nil) then
+   attr_update_functions = {}
+end
+
============================================================
- --- work.cc   02f33f9a20217a5ceaf213e892e66a41a2780441
+++ work.cc     99ee8ae1f14fd0212d72cf853b4e2efcb02c938e
@@ -208,6 +208,92 @@ void
 }
 
 void
+perform_attr_update(std::vector<file_path> const & paths, app_state &
app) +{
+ 
+   std::vector<std::string> avail_funcs;
+   bool get_update_func_ok =
app.lua.hook_get_avail_attr_update_functions(avail_funcs);
+   E(get_update_func_ok, F("Failed to find attribute update
functions"));
+   if (!get_update_func_ok) 
+     {
+       return;
+     }
+ 
+   roster_t old_roster, new_roster;
+   temp_node_id_source nis;
+ 
+   app.require_workspace();
+   get_base_and_current_roster_shape(old_roster, new_roster, nis,
app); 
+   
+   std::vector<file_path> exclude_file_paths;
+   // Determine currently tracked files
+   for (std::vector<utf8>::const_iterator i =
app.exclude_patterns.begin(); 
+        i != app.exclude_patterns.end(); ++i) 
+     {
+       exclude_file_paths.push_back(file_path_external(*i));
+     }
+   node_restriction mask(paths, exclude_file_paths, new_roster, app); 
+   editable_roster_base er(new_roster, nis);
+ 
+   node_map const & nodes = new_roster.all_nodes();
+   for (node_map::const_iterator i = nodes.begin(); i != nodes.end();
++i)
+     {
+       node_id nid = i->first;
+       node_t node = i->second;
+ 
+       // Only analyze restriction-included files.
+       if (!mask.includes(new_roster, nid))
+         continue;
+ 
+       split_path sp;
+       new_roster.get_name(nid, sp);
+       file_path name(sp);
+           
+       P(F("Updating attributes for %s") % name);
+       
+       string curval;
+       string newval;
+       bool luaok;
+ 
+       if (path_exists(name))
+         {
+           for (std::vector<string>::const_iterator i =
avail_funcs.begin();
+                i != avail_funcs.end(); ++i)
+             {
+               curval = node->attrs[attr_key(*i)].second();
+               L(FL("Attribute '%s' currently is '%s'") % *i % curval);
+               
+               luaok = app.lua.hook_update_attribute(*i, name, curval,
newval);
+               E(luaok, F("Error doing lua hook_update_attribute for
attribute %s, value %s") % *i % curval);
+               if (curval == newval)
+                 {
+                   L(FL("Skipping; filesystem matches recorded
workspace."));
+                   continue;
+                 } 
+               else
+                 {
+                   if (newval == string(""))
+                     {
+                       L(FL("Clearing attribute"));
+                       er.clear_attr(sp, attr_key(*i));
+                     }
+                   else
+                     {
+                       L(FL("Setting attribute to '%s'") % newval);
+                       er.set_attr(sp, attr_key(*i),
attr_value(newval));
+                     }
+                 }
+             }  
+         }     
+     }
+   cset new_work;
+   make_cset(old_roster, new_roster, new_work);
+   put_work_cset(new_work);
+   // update_any_attrs(app);
+ 
+ }
+ 
+void
 perform_additions(path_set const & paths, app_state & app, bool
recursive) {
   if (paths.empty())
@@ -247,7 +333,7 @@ perform_additions(path_set const & paths
   cset new_work;
   make_cset(base_roster, new_roster, new_work);
   put_work_cset(new_work);
- -  update_any_attrs(app);
+  //  update_any_attrs(app);
 }
 
 void
@@ -315,7 +401,7 @@ perform_deletions(path_set const & paths
   cset new_work;
   make_cset(base_roster, new_roster, new_work);
   put_work_cset(new_work);
- -  update_any_attrs(app);
+  // update_any_attrs(app);
 }
 
 static void
@@ -439,7 +525,7 @@ perform_rename(set<file_path> const & sr
             }
         }
     }
- -  update_any_attrs(app);
+  // update_any_attrs(app);
 }
 
 void
@@ -502,7 +588,7 @@ perform_pivot_root(file_path const & new
       editable_working_tree e(app, efcs);
       cs.apply_to(e);
     }
- -  update_any_attrs(app);
+  // update_any_attrs(app);
 }
 
 
@@ -1041,7 +1127,8 @@ editable_working_tree::clear_attr(split_
 editable_working_tree::clear_attr(split_path const & pth,
                                   attr_key const & name)
 {
- -  // FIXME_ROSTERS: call a lua hook
+  file_path pth_unsplit(pth);
+  app.lua.hook_apply_attribute(name(), pth_unsplit, "");  
 }
 
 void
@@ -1049,7 +1136,8 @@ editable_working_tree::set_attr(split_pa
                                 attr_key const & name,
                                 attr_value const & val)
 {
- -  // FIXME_ROSTERS: call a lua hook
+  file_path pth_unsplit(pth);
+  app.lua.hook_apply_attribute(name(), pth_unsplit, val());
 }
 
 void
============================================================
- --- work.hh   7634d8afc541e4a1ddc3e770b033e058338601de
+++ work.hh     0229f6f68b577fcb30bcb0f1084d1bd500c9052f
@@ -90,6 +90,10 @@ perform_pivot_root(file_path const & new
 perform_pivot_root(file_path const & new_root, file_path const &
put_old, app_state & app);
 
+void
+perform_attr_update(std::vector<file_path> const & paths, app_state &
app); +
+
 // the "work" file contains the current cset representing uncommitted
 // add/drop/rename operations (not deltas)
 


- --
86 F5 81 A5 D4 2E 1F 1C      http://gnupg.org
And that's my crabbing done for the day.  Got it out of the way early, 
now I have the rest of the afternoon to sniff fragrant tea-roses or 
strangle cute bunnies or something.   -- Michael Devore
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFE5Ap/hvWBpdQuHxwRAkprAJwM8kttpIYIcXwL3dDiQKnATT1JtgCaAy9W
YyOFRnbPztAYwv3pEjm5TOg=
=4NmV
-----END PGP SIGNATURE-----

reply via email to

[Prev in Thread] Current Thread [Next in Thread]