synqa 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|