defop :MkDir, [:dir] do define_method :check do File.directory? @dir end define_method :do do mkdir @dir end define_method :undo do rmdir @dir if File.exist? @dir and Dir.empty? @dir end define_method :inspect do "#" end end defop :SymLink, [:from, :to] do define_method :check do if File.exist? @to or File.symlink? @to # broken symlink should be kept if !(File.symlink? @to) or (File.readlink @to) != @from raise "File '#{@to}' exists but is not a symlink to '#{@from}'" else true end end end define_method :do do ln @from, @to end define_method :undo do rm @to end define_method :inspect do "# '#{to}>" end end defdeploy :tree do |src:, dst:, ignores: [/~$/], stops: []| sp, dp = [src, dst].map {|p| File.expand_path p } src = lambda {|path| File.join sp, path } dst = lambda {|path| File.join dp, path } recur = lambda do |path| return if ignores.any? {|pat| path =~ pat } if File.directory?(src[path]) if stops.include? path op SymLink, from: src[path], to: dst[path] else op MkDir, dir: dst[path] (ls src[path]).each {|p| recur[File.join path, p] } end else op SymLink, from: src[path], to: dst[path] end end (ls sp).each {|path| recur[path] } end