synqa 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/examples/sample-rakefile +8 -21
- data/examples/synqa-useage.rb +2 -1
- data/lib/based-directory.rb +177 -0
- data/lib/synqa.rb +36 -54
- data/test/data/dir1/dir2/dir4/dir5/file6.text +1 -0
- data/test/data/dir1/dir2/dir4/file5.text +1 -0
- data/test/data/dir1/dir2/file3.txt +1 -0
- data/test/data/dir1/dir3/file1.txt +1 -0
- data/test/data/dir1/file1.txt +1 -0
- data/test/data/dir1/file2.txt +1 -0
- data/test/test_based_directory.rb +114 -0
- metadata +20 -11
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/examples/sample-rakefile
CHANGED
@@ -1,33 +1,21 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# In this example the source files are copied directly from ./src to
|
4
|
-
# yourusername@yourhostname.example.com/home/username/public.
|
5
|
-
#
|
6
|
-
# For a more complex static site, your rakefile might generate the site
|
7
|
-
# into an output directory and upload from there.
|
8
|
-
#
|
9
|
-
# Tasks:
|
10
|
-
# clean - removes the cached content files
|
11
|
-
# upload - syncs local content with remote dir (i.e. uploads new/changed files
|
12
|
-
# and deletes remote files that don't exist in the local dir
|
13
|
-
# uploaddry - a "dry run" for upload, doesn't actually upload or delete files
|
14
|
-
|
15
|
-
require 'rejinnirate-rake'
|
16
|
-
require 'synqa' # This assumes synqa is installed as a gem, otherwise require 'synqa.rb'
|
1
|
+
require 'based-directory'
|
2
|
+
require 'synqa'
|
17
3
|
require 'digest/sha2'
|
18
4
|
|
19
5
|
STDOUT.sync = true
|
20
6
|
|
21
|
-
include Rejinnirate
|
22
7
|
include Synqa
|
23
8
|
|
24
9
|
BASE_DIR = File.dirname(__FILE__)
|
25
10
|
|
26
11
|
SRC_DIR = File.join(BASE_DIR, "src")
|
27
|
-
|
12
|
+
|
13
|
+
UPLOAD_DIR = Based::BaseDirectory.new(SRC_DIR,
|
14
|
+
:fileExclude => lambda{|file| file.name.end_with?("~")})
|
15
|
+
|
28
16
|
SYNQA_DIR = File.join(BASE_DIR, "output", "synqa")
|
29
17
|
|
30
|
-
task :default => [:
|
18
|
+
task :default => [:uploaddry] do |t|
|
31
19
|
end
|
32
20
|
|
33
21
|
REMOTE_HOST = SshContentHost.new("yourusername@yourhostname.example.com",
|
@@ -39,8 +27,7 @@ REMOTE_SITE = RemoteContentLocation.new(REMOTE_HOST,
|
|
39
27
|
|
40
28
|
LOCAL_SITE = LocalContentLocation.new(UPLOAD_DIR,
|
41
29
|
Digest::SHA256,
|
42
|
-
File.join(SYNQA_DIR, "localContent.txt")
|
43
|
-
:excludes => ["*\\~", "**/*\\~"])
|
30
|
+
File.join(SYNQA_DIR, "localContent.txt"))
|
44
31
|
|
45
32
|
task :init do |t|
|
46
33
|
ensureDirectoryExists(SYNQA_DIR)
|
data/examples/synqa-useage.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# Sample code for synqa useage -- you will need to fill in your own details
|
2
2
|
|
3
3
|
require 'synqa.rb'
|
4
|
+
require 'based-directory'
|
4
5
|
require 'digest/sha2'
|
5
6
|
|
6
7
|
STDOUT.sync = true
|
@@ -9,7 +10,7 @@ include Synqa
|
|
9
10
|
sha256Sum = Sha256SumCommand.new() # sha256sum (with 2 characters between hash and file name)
|
10
11
|
sha256 = Sha256Command.new() # sha256 -r (with 1 space between hash and file name)
|
11
12
|
|
12
|
-
localContentLocation = LocalContentLocation.new("c:/dev/src/project",
|
13
|
+
localContentLocation = LocalContentLocation.new(Based::BaseDirectory.new("c:/dev/src/project"),
|
13
14
|
Digest::SHA256,
|
14
15
|
"c:/temp/synqa/local.project.content.cache.txt")
|
15
16
|
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# The Based module supports the concept of a "based" directory. Typically in modern software development,
|
2
|
+
# a project is represented by a set of sub-directories and files within a base directory. The exact location
|
3
|
+
# of the base directory is not so important (i.e. it's wherever you checked it out of source control). For a given
|
4
|
+
# file or sub-directory, one is often more interested in the path relative to the base directory, rather than
|
5
|
+
# the absolute path. (But you still need the full path when performing an actual file operation on the file
|
6
|
+
# or directory.)
|
7
|
+
# Also, there might be files and directories that you wish to ignore. Based supports simple functional includes and
|
8
|
+
# excludes. (A bit less succint than include/exclude globs, but probably more flexible.)
|
9
|
+
|
10
|
+
module Based
|
11
|
+
|
12
|
+
# A base class for directories: i.e. either the base directory itself, or a sub-directory
|
13
|
+
class Directory
|
14
|
+
# The base directory (object)
|
15
|
+
attr_reader :base
|
16
|
+
|
17
|
+
# The path of this directory relative to the base directory (includes a following "/" if non-empty)
|
18
|
+
attr_reader :relativePath
|
19
|
+
|
20
|
+
# The elements of the relative path as an array
|
21
|
+
attr_reader :pathElements
|
22
|
+
|
23
|
+
# The immediate name of the directory (nil for the base directory)
|
24
|
+
attr_reader :name
|
25
|
+
|
26
|
+
# The parent directory (nil for the base directory)
|
27
|
+
attr_reader :parent
|
28
|
+
|
29
|
+
# The full path of the file
|
30
|
+
attr_reader :fullPath
|
31
|
+
|
32
|
+
# initialise with un-initialised entries
|
33
|
+
def initialize
|
34
|
+
@entries = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
# get the "entries", i.e. list of files and directories immediately contained in this directory, and cache them.
|
38
|
+
# Note that dirExclude, fileInclude and fileExclude functions in the base directory object
|
39
|
+
# may be applied to filter out some entries.
|
40
|
+
def getEntries
|
41
|
+
if @entries == nil
|
42
|
+
@entries = Dir.entries(fullPath)
|
43
|
+
@dirs = []
|
44
|
+
@files = []
|
45
|
+
for entry in @entries
|
46
|
+
if entry != "." and entry != ".."
|
47
|
+
fullEntryPath = fullPath + entry
|
48
|
+
if ::File.directory?(fullEntryPath)
|
49
|
+
subDirectory = SubDirectory.new(entry, self)
|
50
|
+
if @base.dirExclude == nil or not @base.dirExclude.call(subDirectory)
|
51
|
+
@dirs << subDirectory
|
52
|
+
end
|
53
|
+
elsif ::File.file?(fullEntryPath)
|
54
|
+
file = File.new(entry, self)
|
55
|
+
if @base.fileInclude == nil or @base.fileInclude.call(file)
|
56
|
+
if @base.fileExclude == nil or not @base.fileExclude.call(file)
|
57
|
+
@files << file
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
@dirs.sort_by! {|dir| dir.name}
|
64
|
+
@files.sort_by! {|file| file.name}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Get list of files immediately contained in this directory
|
69
|
+
def files
|
70
|
+
getEntries()
|
71
|
+
return @files
|
72
|
+
end
|
73
|
+
|
74
|
+
# Get list of directories immediately contained in this directory
|
75
|
+
def dirs
|
76
|
+
getEntries()
|
77
|
+
return @dirs
|
78
|
+
end
|
79
|
+
|
80
|
+
# Get a list of all the sub-directories of this directory (with parents preceding children)
|
81
|
+
def subDirs
|
82
|
+
result = []
|
83
|
+
for dir in dirs
|
84
|
+
result << dir
|
85
|
+
result += dir.subDirs
|
86
|
+
end
|
87
|
+
return result
|
88
|
+
end
|
89
|
+
|
90
|
+
# Get a list of all files contained within this directory
|
91
|
+
def allFiles
|
92
|
+
result = files
|
93
|
+
for subDir in subDirs
|
94
|
+
result += subDir.files
|
95
|
+
end
|
96
|
+
return result
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# An object representing a sub-directory (i.e. not the base directory itself)
|
101
|
+
class SubDirectory<Directory
|
102
|
+
|
103
|
+
# Construct directory object from parent directory object and this directory's name
|
104
|
+
def initialize(name, parent)
|
105
|
+
super()
|
106
|
+
@name = name
|
107
|
+
@parent = parent
|
108
|
+
@base = @parent.base
|
109
|
+
@relativePath = @parent.relativePath + @name + "/"
|
110
|
+
@pathElements = @parent.pathElements + [name]
|
111
|
+
@fullPath = @parent.fullPath + @name + "/"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# An object representing the base directory
|
116
|
+
class BaseDirectory<Directory
|
117
|
+
|
118
|
+
# Function to decide if files should be included (if nil, assume all included). Subject
|
119
|
+
# to exclusion by fileExclude
|
120
|
+
attr_reader :fileInclude
|
121
|
+
|
122
|
+
# Function to decide if files should be excluded
|
123
|
+
attr_reader :fileExclude
|
124
|
+
|
125
|
+
# Function to decide if sub-directories should be excluded (if a directory is excluded, so
|
126
|
+
# are all it's sub-directories and files contained within)
|
127
|
+
attr_reader :dirExclude
|
128
|
+
|
129
|
+
# Initialise from absolute file path. Options include :dirExclude, :fileInclude and :fileExclude
|
130
|
+
def initialize(path, options = {})
|
131
|
+
super()
|
132
|
+
@name = nil
|
133
|
+
@parent = nil
|
134
|
+
@base = self
|
135
|
+
@relativePath = ""
|
136
|
+
@pathElements = []
|
137
|
+
@fullPath = path.end_with?("/") ? path : path + "/"
|
138
|
+
@dirExclude = options.fetch(:dirExclude, nil)
|
139
|
+
@fileInclude = options.fetch(:fileInclude, nil)
|
140
|
+
@fileExclude = options.fetch(:fileExclude, nil)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# An object representing a file within the base directory
|
145
|
+
class File
|
146
|
+
# immediate name of file
|
147
|
+
attr_reader :name
|
148
|
+
|
149
|
+
# parent, i.e. containing directory
|
150
|
+
attr_reader :parent
|
151
|
+
|
152
|
+
# the base directory
|
153
|
+
attr_reader :base
|
154
|
+
|
155
|
+
# path of this file relative to base directory
|
156
|
+
attr_reader :relativePath
|
157
|
+
|
158
|
+
# elements of file path (including the name) as an array
|
159
|
+
attr_reader :pathElements
|
160
|
+
|
161
|
+
# full absolute path name of file
|
162
|
+
attr_reader :fullPath
|
163
|
+
|
164
|
+
# initialise from name and containing directory
|
165
|
+
def initialize(name, parent)
|
166
|
+
super()
|
167
|
+
@name = name
|
168
|
+
@parent = parent
|
169
|
+
@base = @parent.base
|
170
|
+
@relativePath = @parent.relativePath + @name
|
171
|
+
@pathElements = @parent.pathElements + [name]
|
172
|
+
@fullPath = @parent.fullPath + @name
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
data/lib/synqa.rb
CHANGED
@@ -2,6 +2,17 @@ require 'time'
|
|
2
2
|
|
3
3
|
module Synqa
|
4
4
|
|
5
|
+
# ensure that a directory exists
|
6
|
+
def ensureDirectoryExists(directoryName)
|
7
|
+
if File.exist? directoryName
|
8
|
+
if not File.directory? directoryName
|
9
|
+
raise "#{directoryName} is a non-directory file"
|
10
|
+
end
|
11
|
+
else
|
12
|
+
FileUtils.makedirs(directoryName)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
5
16
|
# Check if the last executed process exited with status 0, if not, raise an exception
|
6
17
|
def checkProcessStatus(description)
|
7
18
|
processStatus = $?
|
@@ -400,7 +411,7 @@ module Synqa
|
|
400
411
|
def sort!
|
401
412
|
dirs.sort_by! {|dir| dir.name}
|
402
413
|
files.sort_by! {|file| file.name}
|
403
|
-
for dir in dirs
|
414
|
+
for dir in dirs
|
404
415
|
dir.sort!
|
405
416
|
end
|
406
417
|
end
|
@@ -441,10 +452,10 @@ module Synqa
|
|
441
452
|
puts "#{currentIndent} [DELETE]"
|
442
453
|
end
|
443
454
|
nextIndent = currentIndent + indent
|
444
|
-
for dir in dirs
|
455
|
+
for dir in dirs
|
445
456
|
dir.showIndented("#{dir.name}/", indent = indent, currentIndent = nextIndent)
|
446
457
|
end
|
447
|
-
for file in files
|
458
|
+
for file in files
|
448
459
|
puts "#{nextIndent}#{file.name} - #{file.hash}"
|
449
460
|
if file.copyDestination != nil
|
450
461
|
puts "#{nextIndent} [COPY to #{file.copyDestination.fullPath}]"
|
@@ -460,11 +471,11 @@ module Synqa
|
|
460
471
|
if time != nil
|
461
472
|
outFile.puts("T #{time.strftime(@@dateTimeFormat)}\n")
|
462
473
|
end
|
463
|
-
for dir in dirs
|
474
|
+
for dir in dirs
|
464
475
|
outFile.puts("D #{prefix}#{dir.name}\n")
|
465
476
|
dir.writeLinesToFile(outFile, "#{prefix}#{dir.name}/")
|
466
477
|
end
|
467
|
-
for file in files
|
478
|
+
for file in files
|
468
479
|
outFile.puts("F #{file.hash} #{prefix}#{file.name}\n")
|
469
480
|
end
|
470
481
|
end
|
@@ -654,26 +665,16 @@ module Synqa
|
|
654
665
|
# can be calculated directly using Ruby library functions.
|
655
666
|
class LocalContentLocation<ContentLocation
|
656
667
|
|
657
|
-
# the base directory
|
658
|
-
|
668
|
+
# the base directory, for example of type Based::BaseDirectory. Methods invoked are: allFiles, subDirs and fullPath.
|
669
|
+
# For file and dir objects returned by allFiles & subDirs, methods invoked are: relativePath and fullPath
|
670
|
+
attr_reader :baseDirectory
|
659
671
|
# the ruby class that generates the hash, e.g. Digest::SHA256
|
660
672
|
attr_reader :hashClass
|
661
673
|
|
662
|
-
def initialize(
|
674
|
+
def initialize(baseDirectory, hashClass, cachedContentFile = nil)
|
663
675
|
super(cachedContentFile)
|
664
|
-
@
|
665
|
-
@baseDirLen = @baseDir.length
|
676
|
+
@baseDirectory = baseDirectory
|
666
677
|
@hashClass = hashClass
|
667
|
-
@excludeGlobs = options.fetch(:excludes, [])
|
668
|
-
end
|
669
|
-
|
670
|
-
# get the path of a file name relative to the base directory
|
671
|
-
def getRelativePath(fileName)
|
672
|
-
if fileName.start_with? @baseDir
|
673
|
-
return fileName[@baseDirLen..-1]
|
674
|
-
else
|
675
|
-
raise "File name #{fileName} does not start with #{baseDir}"
|
676
|
-
end
|
677
678
|
end
|
678
679
|
|
679
680
|
# get the path as required for an SCP command
|
@@ -683,18 +684,7 @@ module Synqa
|
|
683
684
|
|
684
685
|
# get the full path of a relative path (i.e. of a file/directory within the base directory)
|
685
686
|
def getFullPath(relativePath)
|
686
|
-
return @
|
687
|
-
end
|
688
|
-
|
689
|
-
# is the relative path name excluded by one of the specified exclusion globs?
|
690
|
-
def fileIsExcluded?(relativeFile)
|
691
|
-
for excludeGlob in @excludeGlobs
|
692
|
-
if File.fnmatch(excludeGlob, relativeFile)
|
693
|
-
puts " file #{relativeFile} excluded by glob #{excludeGlob}"
|
694
|
-
return true
|
695
|
-
end
|
696
|
-
end
|
697
|
-
return false
|
687
|
+
return @baseDirectory.fullPath + relativePath
|
698
688
|
end
|
699
689
|
|
700
690
|
# get the content tree for this base directory by iterating over all
|
@@ -709,25 +699,17 @@ module Synqa
|
|
709
699
|
cachedMapOfHashes = cachedTimeAndMapOfHashes[1]
|
710
700
|
contentTree = ContentTree.new()
|
711
701
|
contentTree.time = Time.now.utc
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
cachedDigest = cachedMapOfHashes[relativePath]
|
722
|
-
if cachedTime and cachedDigest and File.stat(fileOrDir).mtime < cachedTime
|
723
|
-
digest = cachedDigest
|
724
|
-
else
|
725
|
-
digest = hashClass.file(fileOrDir).hexdigest
|
726
|
-
end
|
727
|
-
contentTree.addFile(relativePath, digest)
|
728
|
-
end
|
729
|
-
end
|
702
|
+
for subDir in @baseDirectory.subDirs
|
703
|
+
contentTree.addDir(subDir.relativePath)
|
704
|
+
end
|
705
|
+
for file in @baseDirectory.allFiles
|
706
|
+
cachedDigest = cachedMapOfHashes[file.relativePath]
|
707
|
+
if cachedTime and cachedDigest and File.stat(file.fullPath).mtime < cachedTime
|
708
|
+
digest = cachedDigest
|
709
|
+
else
|
710
|
+
digest = hashClass.file(file.fullPath).hexdigest
|
730
711
|
end
|
712
|
+
contentTree.addFile(file.relativePath, digest)
|
731
713
|
end
|
732
714
|
contentTree.sort!
|
733
715
|
if cachedContentFile != nil
|
@@ -892,7 +874,7 @@ module Synqa
|
|
892
874
|
# Recursively perform all marked copy operations from the source content tree to the
|
893
875
|
# destination content tree, or if dryRun, just pretend to perform them.
|
894
876
|
def doCopyOperations(sourceContent, destinationContent, dryRun)
|
895
|
-
for dir in sourceContent.dirs
|
877
|
+
for dir in sourceContent.dirs
|
896
878
|
if dir.copyDestination != nil
|
897
879
|
sourcePath = sourceLocation.getScpPath(dir.fullPath)
|
898
880
|
destinationPath = destinationLocation.getScpPath(dir.copyDestination.fullPath)
|
@@ -901,7 +883,7 @@ module Synqa
|
|
901
883
|
doCopyOperations(dir, destinationContent.getDir(dir.name), dryRun)
|
902
884
|
end
|
903
885
|
end
|
904
|
-
for file in sourceContent.files
|
886
|
+
for file in sourceContent.files
|
905
887
|
if file.copyDestination != nil
|
906
888
|
sourcePath = sourceLocation.getScpPath(file.fullPath)
|
907
889
|
destinationPath = destinationLocation.getScpPath(file.copyDestination.fullPath)
|
@@ -913,7 +895,7 @@ module Synqa
|
|
913
895
|
# Recursively perform all marked delete operations on the destination content tree,
|
914
896
|
# or if dryRun, just pretend to perform them.
|
915
897
|
def doDeleteOperations(destinationContent, dryRun)
|
916
|
-
for dir in destinationContent.dirs
|
898
|
+
for dir in destinationContent.dirs
|
917
899
|
if dir.toBeDeleted
|
918
900
|
dirPath = destinationLocation.getFullPath(dir.fullPath)
|
919
901
|
destinationLocation.ssh("rm -r #{dirPath}", dryRun)
|
@@ -921,7 +903,7 @@ module Synqa
|
|
921
903
|
doDeleteOperations(dir, dryRun)
|
922
904
|
end
|
923
905
|
end
|
924
|
-
for file in destinationContent.files
|
906
|
+
for file in destinationContent.files
|
925
907
|
if file.toBeDeleted
|
926
908
|
filePath = destinationLocation.getFullPath(file.fullPath)
|
927
909
|
destinationLocation.ssh("rm #{filePath}", dryRun)
|
@@ -0,0 +1 @@
|
|
1
|
+
This is file 6.
|
@@ -0,0 +1 @@
|
|
1
|
+
File 5, with different extension.
|
@@ -0,0 +1 @@
|
|
1
|
+
This is a third file, inside a sub-directory.
|
@@ -0,0 +1 @@
|
|
1
|
+
Another file 1
|
@@ -0,0 +1 @@
|
|
1
|
+
This is a file 1.
|
@@ -0,0 +1 @@
|
|
1
|
+
This is a second file.
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
require 'based-directory'
|
4
|
+
|
5
|
+
module Based
|
6
|
+
|
7
|
+
class BaseDirectoryTestCase < Test::Unit::TestCase
|
8
|
+
include Based
|
9
|
+
end
|
10
|
+
|
11
|
+
class TestBaseDirectory < BaseDirectoryTestCase
|
12
|
+
context "A base directory" do
|
13
|
+
setup do
|
14
|
+
@baseDirPath = ::File.expand_path(::File.join(::File.dirname(__FILE__), "data", "dir1"))
|
15
|
+
#puts "@baseDirPath = #{@baseDirPath}"
|
16
|
+
@baseDir = BaseDirectory.new(@baseDirPath)
|
17
|
+
end
|
18
|
+
|
19
|
+
should "not add / if already in base bath" do
|
20
|
+
@baseDir2 = BaseDirectory.new(@baseDirPath + "/")
|
21
|
+
assert_equal "#{@baseDirPath}/", @baseDir.fullPath
|
22
|
+
dir2 = @baseDir.dirs[0]
|
23
|
+
assert_equal "dir2", dir2.name
|
24
|
+
end
|
25
|
+
|
26
|
+
should "find files in top-level directory and get their names and relative paths" do
|
27
|
+
names = @baseDir.files.map {|file| file.name}
|
28
|
+
assert_equal ["file1.txt", "file2.txt"], names
|
29
|
+
relativePaths = @baseDir.files.map {|file| file.relativePath}
|
30
|
+
assert_equal ["file1.txt", "file2.txt"], relativePaths
|
31
|
+
end
|
32
|
+
|
33
|
+
should "check attributes of basedir" do
|
34
|
+
assert_equal nil, @baseDir.name
|
35
|
+
assert_equal nil, @baseDir.parent
|
36
|
+
assert_equal @baseDir, @baseDir.base
|
37
|
+
assert_equal "", @baseDir.relativePath
|
38
|
+
assert_equal [], @baseDir.pathElements
|
39
|
+
assert_equal "#{@baseDirPath}/", @baseDir.fullPath
|
40
|
+
end
|
41
|
+
|
42
|
+
should "find one directory and check all its attributes" do
|
43
|
+
dir2 = @baseDir.dirs[0]
|
44
|
+
dir4 = dir2.dirs[0]
|
45
|
+
assert_equal "dir4", dir4.name
|
46
|
+
assert_equal dir2, dir4.parent
|
47
|
+
assert_equal @baseDir, dir4.base
|
48
|
+
assert_equal "dir2/dir4/", dir4.relativePath
|
49
|
+
assert_equal ["dir2", "dir4"], dir4.pathElements
|
50
|
+
assert_equal "#{@baseDirPath}/dir2/dir4/", dir4.fullPath
|
51
|
+
end
|
52
|
+
|
53
|
+
should "find one file and check all its attributes" do
|
54
|
+
dir2 = @baseDir.dirs[0]
|
55
|
+
dir4 = dir2.dirs[0]
|
56
|
+
file5 = dir4.files[0]
|
57
|
+
assert_equal "file5.text", file5.name
|
58
|
+
assert_equal dir4, file5.parent
|
59
|
+
assert_equal @baseDir, file5.base
|
60
|
+
assert_equal "dir2/dir4/file5.text", file5.relativePath
|
61
|
+
assert_equal ["dir2", "dir4", "file5.text"], file5.pathElements
|
62
|
+
assert_equal "#{@baseDirPath}/dir2/dir4/file5.text", file5.fullPath
|
63
|
+
end
|
64
|
+
|
65
|
+
should "find sub-directories in top-level directory and get their names and relative paths" do
|
66
|
+
names = @baseDir.dirs.map {|dir| dir.name}
|
67
|
+
assert_equal ["dir2", "dir3"], names
|
68
|
+
relativePaths = @baseDir.dirs.map {|dir| dir.relativePath}
|
69
|
+
assert_equal ["dir2/", "dir3/"], relativePaths
|
70
|
+
end
|
71
|
+
|
72
|
+
should "find all sub-directories of base directory" do
|
73
|
+
relativePaths = @baseDir.subDirs.map{|dir| dir.relativePath}
|
74
|
+
assert_equal ["dir2/", "dir2/dir4/", "dir2/dir4/dir5/", "dir3/"], relativePaths
|
75
|
+
end
|
76
|
+
|
77
|
+
should "find all files within base directory" do
|
78
|
+
relativePaths = @baseDir.allFiles.map{|dir| dir.relativePath}
|
79
|
+
assert_equal ["file1.txt", "file2.txt", "dir2/file3.txt", "dir2/dir4/file5.text",
|
80
|
+
"dir2/dir4/dir5/file6.text", "dir3/file1.txt"], relativePaths
|
81
|
+
end
|
82
|
+
|
83
|
+
should "exclude dir2" do
|
84
|
+
filteredBaseDir = BaseDirectory.new(@baseDirPath,
|
85
|
+
:dirExclude => lambda{|dir| dir.name == "dir2"})
|
86
|
+
relativePaths = filteredBaseDir.allFiles.map{|file| file.relativePath}
|
87
|
+
assert_equal ["file1.txt", "file2.txt", "dir3/file1.txt"], relativePaths
|
88
|
+
end
|
89
|
+
|
90
|
+
should "include only .txt files" do
|
91
|
+
filteredBaseDir = BaseDirectory.new(@baseDirPath,
|
92
|
+
:fileInclude => lambda{|file| file.name.end_with? ".txt"})
|
93
|
+
relativePaths = filteredBaseDir.allFiles.map{|file| file.relativePath}
|
94
|
+
assert_equal ["file1.txt", "file2.txt", "dir2/file3.txt",
|
95
|
+
"dir3/file1.txt"], relativePaths
|
96
|
+
end
|
97
|
+
|
98
|
+
should "not include .txt files" do
|
99
|
+
filteredBaseDir = BaseDirectory.new(@baseDirPath,
|
100
|
+
:fileExclude => lambda{|file| file.name.end_with? ".txt"})
|
101
|
+
relativePaths = filteredBaseDir.allFiles.map{|file| file.relativePath}
|
102
|
+
assert_equal ["dir2/dir4/file5.text", "dir2/dir4/dir5/file6.text"], relativePaths
|
103
|
+
end
|
104
|
+
|
105
|
+
should "include only .txt files not in dir3" do
|
106
|
+
filteredBaseDir = BaseDirectory.new(@baseDirPath,
|
107
|
+
:dirExclude => lambda{|dir| dir.name == "dir3"},
|
108
|
+
:fileInclude => lambda{|file| file.name.end_with? ".txt"})
|
109
|
+
relativePaths = filteredBaseDir.allFiles.map{|file| file.relativePath}
|
110
|
+
assert_equal ["file1.txt", "file2.txt", "dir2/file3.txt"], relativePaths
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: synqa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-03-
|
12
|
+
date: 2011-03-19 00:00:00.000000000 +13:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: shoulda
|
17
|
-
requirement: &
|
17
|
+
requirement: &24879420 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *24879420
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: bundler
|
28
|
-
requirement: &
|
28
|
+
requirement: &24878820 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ~>
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: 1.0.0
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *24878820
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: jeweler
|
39
|
-
requirement: &
|
39
|
+
requirement: &24878220 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ~>
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: 1.5.2
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *24878220
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: rcov
|
50
|
-
requirement: &
|
50
|
+
requirement: &24877560 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,7 +55,7 @@ dependencies:
|
|
55
55
|
version: '0'
|
56
56
|
type: :development
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *24877560
|
59
59
|
description: Sync files from a local directory to a remote directory via SSH/SCP
|
60
60
|
email: http://www.1729.com/email.html
|
61
61
|
executables: []
|
@@ -74,8 +74,16 @@ files:
|
|
74
74
|
- _project.el
|
75
75
|
- examples/sample-rakefile
|
76
76
|
- examples/synqa-useage.rb
|
77
|
+
- lib/based-directory.rb
|
77
78
|
- lib/synqa.rb
|
79
|
+
- test/data/dir1/dir2/dir4/dir5/file6.text
|
80
|
+
- test/data/dir1/dir2/dir4/file5.text
|
81
|
+
- test/data/dir1/dir2/file3.txt
|
82
|
+
- test/data/dir1/dir3/file1.txt
|
83
|
+
- test/data/dir1/file1.txt
|
84
|
+
- test/data/dir1/file2.txt
|
78
85
|
- test/helper.rb
|
86
|
+
- test/test_based_directory.rb
|
79
87
|
- test/test_synqa.rb
|
80
88
|
has_rdoc: true
|
81
89
|
homepage: http://www.1729.com/software/synqa/
|
@@ -93,7 +101,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
93
101
|
version: '0'
|
94
102
|
segments:
|
95
103
|
- 0
|
96
|
-
hash:
|
104
|
+
hash: 537622927
|
97
105
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
106
|
none: false
|
99
107
|
requirements:
|
@@ -109,4 +117,5 @@ summary: Sync files from a local directory to a remote directory via SSH/SCP
|
|
109
117
|
test_files:
|
110
118
|
- examples/synqa-useage.rb
|
111
119
|
- test/helper.rb
|
120
|
+
- test/test_based_directory.rb
|
112
121
|
- test/test_synqa.rb
|