amp-core 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/.document +5 -0
- data/.gitignore +23 -0
- data/Gemfile +11 -0
- data/LICENSE +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +67 -0
- data/VERSION +1 -0
- data/features/amp-core.feature +9 -0
- data/features/step_definitions/amp-core_steps.rb +0 -0
- data/features/support/env.rb +4 -0
- data/lib/amp-core.rb +53 -0
- data/lib/amp-core/command_ext/repository_loading.rb +31 -0
- data/lib/amp-core/repository/abstract/abstract_changeset.rb +113 -0
- data/lib/amp-core/repository/abstract/abstract_local_repo.rb +208 -0
- data/lib/amp-core/repository/abstract/abstract_staging_area.rb +202 -0
- data/lib/amp-core/repository/abstract/abstract_versioned_file.rb +116 -0
- data/lib/amp-core/repository/abstract/common_methods/changeset.rb +185 -0
- data/lib/amp-core/repository/abstract/common_methods/local_repo.rb +293 -0
- data/lib/amp-core/repository/abstract/common_methods/staging_area.rb +248 -0
- data/lib/amp-core/repository/abstract/common_methods/versioned_file.rb +87 -0
- data/lib/amp-core/repository/generic_repo_picker.rb +94 -0
- data/lib/amp-core/repository/repository.rb +41 -0
- data/lib/amp-core/support/encoding_utils.rb +46 -0
- data/lib/amp-core/support/platform_utils.rb +92 -0
- data/lib/amp-core/support/rooted_opener.rb +143 -0
- data/lib/amp-core/support/string_utils.rb +86 -0
- data/lib/amp-core/templates/git/blank.log.erb +18 -0
- data/lib/amp-core/templates/git/default.log.erb +18 -0
- data/lib/amp-core/templates/mercurial/blank.commit.erb +23 -0
- data/lib/amp-core/templates/mercurial/blank.log.erb +18 -0
- data/lib/amp-core/templates/mercurial/default.commit.erb +23 -0
- data/lib/amp-core/templates/mercurial/default.log.erb +26 -0
- data/lib/amp-core/templates/template.rb +202 -0
- data/spec/amp-core_spec.rb +11 -0
- data/spec/command_ext_specs/repository_loading_spec.rb +64 -0
- data/spec/command_ext_specs/spec_helper.rb +1 -0
- data/spec/repository_specs/repository_spec.rb +41 -0
- data/spec/repository_specs/spec_helper.rb +1 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support_specs/encoding_utils_spec.rb +69 -0
- data/spec/support_specs/platform_utils_spec.rb +33 -0
- data/spec/support_specs/spec_helper.rb +1 -0
- data/spec/support_specs/string_utils_spec.rb +44 -0
- data/test/test_templates.rb +81 -0
- metadata +157 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
##################################################################
|
2
|
+
# Licensing Information #
|
3
|
+
# #
|
4
|
+
# The following code is licensed, as standalone code, under #
|
5
|
+
# the Ruby License, unless otherwise directed within the code. #
|
6
|
+
# #
|
7
|
+
# For information on the license of this code when distributed #
|
8
|
+
# with and used in conjunction with the other modules in the #
|
9
|
+
# Amp project, please see the root-level LICENSE file. #
|
10
|
+
# #
|
11
|
+
# © Michael J. Edgar and Ari Brown, 2009-2010 #
|
12
|
+
# #
|
13
|
+
##################################################################
|
14
|
+
|
15
|
+
module Amp
|
16
|
+
module Core
|
17
|
+
module Repositories
|
18
|
+
|
19
|
+
##
|
20
|
+
# = CommonVersionedFileMethods
|
21
|
+
#
|
22
|
+
# These methods are common to all repositories, and this module is mixed into
|
23
|
+
# the AbstractLocalRepository class. This guarantees that all repositories will
|
24
|
+
# have these methods.
|
25
|
+
#
|
26
|
+
# No methods should be placed into this module unless it relies on methods in the
|
27
|
+
# general API for repositories.
|
28
|
+
module CommonVersionedFileMethods
|
29
|
+
|
30
|
+
def unified_diff_with(other_vf, opts = {})
|
31
|
+
Diffs::Mercurial::MercurialDiff.unified_diff(self.data, self.changeset.easy_date,
|
32
|
+
other_vf.data, other_vf.changeset.easy_date,
|
33
|
+
self.path, other_vf.path || "/dev/null",
|
34
|
+
false, opts)
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Compares two versioned files - namely, their data.
|
39
|
+
#
|
40
|
+
# @param [VersionedFile] other what to compare to
|
41
|
+
# @return [Boolean] true if the two are the same
|
42
|
+
def ===(other)
|
43
|
+
self.path == other.path &&
|
44
|
+
self.data == other.data
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns if the file has been changed since its parent. Slow.
|
48
|
+
# If your implementation has a fast way of doing this, we recommend
|
49
|
+
# you override this method.
|
50
|
+
#
|
51
|
+
# @return [Boolean] has the file been changed since its parent?
|
52
|
+
def clean?
|
53
|
+
self === parents.first
|
54
|
+
end
|
55
|
+
opposite_method :dirty?, :clean?
|
56
|
+
|
57
|
+
##
|
58
|
+
# User who committed this revision to this file
|
59
|
+
#
|
60
|
+
# @return [String] the user
|
61
|
+
def user; changeset.user; end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Date this revision to this file was committed
|
65
|
+
#
|
66
|
+
# @return [DateTime]
|
67
|
+
def date; changeset.date; end
|
68
|
+
|
69
|
+
##
|
70
|
+
# The description of the commit that contained this file revision
|
71
|
+
#
|
72
|
+
# @return [String]
|
73
|
+
def description; changeset.description; end
|
74
|
+
|
75
|
+
##
|
76
|
+
# The branch this tracked file belongs to
|
77
|
+
#
|
78
|
+
# @return [String]
|
79
|
+
def branch; changeset.branch; end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Working directory has no children!
|
83
|
+
def children; []; end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
##################################################################
|
2
|
+
# Licensing Information #
|
3
|
+
# #
|
4
|
+
# The following code is licensed, as standalone code, under #
|
5
|
+
# the Ruby License, unless otherwise directed within the code. #
|
6
|
+
# #
|
7
|
+
# For information on the license of this code when distributed #
|
8
|
+
# with and used in conjunction with the other modules in the #
|
9
|
+
# Amp project, please see the root-level LICENSE file. #
|
10
|
+
# #
|
11
|
+
# © Michael J. Edgar and Ari Brown, 2009-2010 #
|
12
|
+
# #
|
13
|
+
##################################################################
|
14
|
+
|
15
|
+
module Amp
|
16
|
+
module Core
|
17
|
+
module Repositories
|
18
|
+
|
19
|
+
##
|
20
|
+
# This class is a generic "repo picker". It will return a Repository object
|
21
|
+
# for the given path (if there is one), and is capable of telling you if there
|
22
|
+
# is a repository of its type in the given directory.
|
23
|
+
#
|
24
|
+
# Amp started off with a MercurialPicker - it knows how to find Mercurial repos.
|
25
|
+
#
|
26
|
+
# When amp runs, it iterates over all subclasses of AbstractRepoPicker, in no
|
27
|
+
# guaranteed order (so don't stomp on existing pickers!), calling #repo_in_dir? .
|
28
|
+
# If only one picker returns +true+, then that picker is used for opening the
|
29
|
+
# repository. If more than one returns +true+, the user's configuration is consulted.
|
30
|
+
# If nothing is found then, then the user is prompted. When the final picker has been
|
31
|
+
# chosen, its #pick method is called to get the repository for the directory/URL.
|
32
|
+
#
|
33
|
+
# This is an "abstract" class, in that all the methods will raise a NotImplementedError
|
34
|
+
# if you try to call them.
|
35
|
+
#
|
36
|
+
# You must subclass this class, or your custom repo code will be ignored by Amp's
|
37
|
+
# dispatch system.
|
38
|
+
class GenericRepoPicker
|
39
|
+
@all_pickers = []
|
40
|
+
class << self
|
41
|
+
include Enumerable
|
42
|
+
attr_accessor :all_pickers
|
43
|
+
|
44
|
+
##
|
45
|
+
# Iterate over every RepoPicker in the system.
|
46
|
+
def each(*args, &block)
|
47
|
+
@all_pickers.each(*args, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
##
|
53
|
+
# Assuming you're a Ruby Newbie reading this: The interpreter calls
|
54
|
+
# {{inherited}} on the superclass when a class is subclassed.
|
55
|
+
#
|
56
|
+
# For the non-newbies, we're just keeping track of all subclasses so
|
57
|
+
# we know what classes we can pick from.
|
58
|
+
#
|
59
|
+
# @param [Class] subclass the class that just inherited from this class
|
60
|
+
def inherited(subclass)
|
61
|
+
all_pickers << subclass.new
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Returns whether or not there is a repository in the given directory. This
|
67
|
+
# picker should only be responsible for one type of repository - git, svn, hg,
|
68
|
+
# etc. The given path could be deep inside a repository, and must look in parent
|
69
|
+
# directories for the root of the VCS repository.
|
70
|
+
#
|
71
|
+
# @param [String] path the path in which to search for a repository
|
72
|
+
# @return [Boolean] is there a repository in this directory (or parent directories)?
|
73
|
+
def repo_in_dir?(path)
|
74
|
+
raise NotImplementedError.new("repo_in_dir? must be implemented in a concrete subclass.")
|
75
|
+
end
|
76
|
+
alias_method :repo_in_url?, :repo_in_dir?
|
77
|
+
|
78
|
+
##
|
79
|
+
# Returns a repository object for the given path. Should respond to the standard repository
|
80
|
+
# API to the best of its ability, and raise a CapabilityError if asked to do something it
|
81
|
+
# cannot do from the API.
|
82
|
+
#
|
83
|
+
# @param [AmpConfig] config the configuration of the current environment, loaded from
|
84
|
+
# appropriate configuration files
|
85
|
+
# @param [String] path the path/URL in which to open the repository.
|
86
|
+
# @param [Boolean] create should a repository be created in the given directory/URL?
|
87
|
+
# @return [AbstractLocalRepository] the repository for the given URL
|
88
|
+
def pick(config, path = '', create = false)
|
89
|
+
raise NotImplementedError.new("repo_in_dir? must be implemented in a concrete subclass.")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
##################################################################
|
2
|
+
# Licensing Information #
|
3
|
+
# #
|
4
|
+
# The following code is licensed, as standalone code, under #
|
5
|
+
# the Ruby License, unless otherwise directed within the code. #
|
6
|
+
# #
|
7
|
+
# For information on the license of this code when distributed #
|
8
|
+
# with and used in conjunction with the other modules in the #
|
9
|
+
# Amp project, please see the root-level LICENSE file. #
|
10
|
+
# #
|
11
|
+
# © Michael J. Edgar and Ari Brown, 2009-2010 #
|
12
|
+
# #
|
13
|
+
##################################################################
|
14
|
+
|
15
|
+
module Amp
|
16
|
+
module Core
|
17
|
+
module Repositories
|
18
|
+
class RepoError < StandardError; end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Picks a repository provided a user configuration, a path, and whether
|
22
|
+
# we have permission to create the repository.
|
23
|
+
#
|
24
|
+
# This is the entry point for repo-independent command dispatch. We need
|
25
|
+
# to know if the given repository is of a particular type. We iterate
|
26
|
+
# over all known types, ask each type "does this path look like your kind
|
27
|
+
# of repo?", and if it says "yes", use that type.
|
28
|
+
#
|
29
|
+
# Note: this does NOT handle when there are two types of repositories in
|
30
|
+
# a given directory.
|
31
|
+
def self.pick(config, path='', create=false)
|
32
|
+
GenericRepoPicker.each do |picker|
|
33
|
+
return picker.pick(config, path, create) if picker.repo_in_dir?(path)
|
34
|
+
end
|
35
|
+
|
36
|
+
# We have found... nothing
|
37
|
+
nil
|
38
|
+
end # def self.pick
|
39
|
+
end # module Repositories
|
40
|
+
end # module Core
|
41
|
+
end # module Amp
|
@@ -0,0 +1,46 @@
|
|
1
|
+
##################################################################
|
2
|
+
# Licensing Information #
|
3
|
+
# #
|
4
|
+
# The following code is licensed, as standalone code, under #
|
5
|
+
# the Ruby License, unless otherwise directed within the code. #
|
6
|
+
# #
|
7
|
+
# For information on the license of this code when distributed #
|
8
|
+
# with and used in conjunction with the other modules in the #
|
9
|
+
# Amp project, please see the root-level LICENSE file. #
|
10
|
+
# #
|
11
|
+
# © Michael J. Edgar and Ari Brown, 2009-2010 #
|
12
|
+
# #
|
13
|
+
##################################################################
|
14
|
+
|
15
|
+
module Amp
|
16
|
+
module Core
|
17
|
+
module Support
|
18
|
+
# This module is a set of string functions that we use frequently.
|
19
|
+
# They sued to be monkey-patched onto the String class, but we don't
|
20
|
+
# do that anymore.
|
21
|
+
module EncodingUtils
|
22
|
+
module_function
|
23
|
+
|
24
|
+
##
|
25
|
+
# Used for byte-swapping a 64-bit double long.
|
26
|
+
# Unfortuantely, this will invoke bignum logic, which is ridiculously slow.
|
27
|
+
# That's why we have a C extension.
|
28
|
+
#
|
29
|
+
# If the system is little endian, we work some magic. If the system is big
|
30
|
+
# endian, we just return self.
|
31
|
+
#
|
32
|
+
# @return [Integer] the number swapped as if it were a 64-bit integer
|
33
|
+
def network_to_host_64(src)
|
34
|
+
if Amp::Core::Support::Platform::SYSTEM[:endian] == :little
|
35
|
+
((src >> 56)) | ((src & 0x00FF000000000000) >> 40) |
|
36
|
+
((src & 0x0000FF0000000000) >> 24) | ((src & 0x000000FF00000000) >> 8 ) |
|
37
|
+
((src & 0x00000000FF000000) << 8 ) | ((src & 0x0000000000FF0000) << 24) |
|
38
|
+
((src & 0x000000000000FF00) << 40) | ((src & 0x00000000000000FF) << 56)
|
39
|
+
else
|
40
|
+
src
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
##################################################################
|
2
|
+
# Licensing Information #
|
3
|
+
# #
|
4
|
+
# The following code is licensed, as standalone code, under #
|
5
|
+
# the Ruby License, unless otherwise directed within the code. #
|
6
|
+
# #
|
7
|
+
# For information on the license of this code when distributed #
|
8
|
+
# with and used in conjunction with the other modules in the #
|
9
|
+
# Amp project, please see the root-level LICENSE file. #
|
10
|
+
# #
|
11
|
+
# © Michael J. Edgar and Ari Brown, 2009-2010 #
|
12
|
+
# #
|
13
|
+
##################################################################
|
14
|
+
module Amp
|
15
|
+
module Core
|
16
|
+
module Support
|
17
|
+
# This module is used to set a few constants regarding which OS,
|
18
|
+
# implementation, and architecture the user is running.
|
19
|
+
module Platform
|
20
|
+
if RUBY_PLATFORM =~ /darwin/i
|
21
|
+
OS = :unix
|
22
|
+
IMPL = :macosx
|
23
|
+
elsif RUBY_PLATFORM =~ /linux/i
|
24
|
+
OS = :unix
|
25
|
+
IMPL = :linux
|
26
|
+
elsif RUBY_PLATFORM =~ /freebsd/i
|
27
|
+
OS = :unix
|
28
|
+
IMPL = :freebsd
|
29
|
+
elsif RUBY_PLATFORM =~ /netbsd/i
|
30
|
+
OS = :unix
|
31
|
+
IMPL = :netbsd
|
32
|
+
elsif RUBY_PLATFORM =~ /mswin/i
|
33
|
+
OS = :win32
|
34
|
+
IMPL = :mswin
|
35
|
+
elsif RUBY_PLATFORM =~ /cygwin/i
|
36
|
+
OS = :unix
|
37
|
+
IMPL = :cygwin
|
38
|
+
elsif RUBY_PLATFORM =~ /mingw/i
|
39
|
+
OS = :win32
|
40
|
+
IMPL = :mingw
|
41
|
+
elsif RUBY_PLATFORM =~ /bccwin/i
|
42
|
+
OS = :win32
|
43
|
+
IMPL = :bccwin
|
44
|
+
elsif RUBY_PLATFORM =~ /wince/i
|
45
|
+
OS = :win32
|
46
|
+
IMPL = :wince
|
47
|
+
elsif RUBY_PLATFORM =~ /vms/i
|
48
|
+
OS = :vms
|
49
|
+
IMPL = :vms
|
50
|
+
elsif RUBY_PLATFORM =~ /os2/i
|
51
|
+
OS = :os2
|
52
|
+
IMPL = :os2 # maybe there is some better choice here?
|
53
|
+
else
|
54
|
+
OS = :unknown
|
55
|
+
IMPL = :unknown
|
56
|
+
end
|
57
|
+
|
58
|
+
if RUBY_PLATFORM =~ /(i\d86)/i
|
59
|
+
ARCH = :x86
|
60
|
+
elsif RUBY_PLATFORM =~ /(x86_64|amd64)/i
|
61
|
+
ARCH = :x86_64
|
62
|
+
elsif RUBY_PLATFORM =~ /ia64/i
|
63
|
+
ARCH = :ia64
|
64
|
+
elsif RUBY_PLATFORM =~ /powerpc/i
|
65
|
+
ARCH = :powerpc
|
66
|
+
elsif RUBY_PLATFORM =~ /alpha/i
|
67
|
+
ARCH = :alpha
|
68
|
+
elsif RUBY_PLATFORM =~ /universal/i
|
69
|
+
ARCH = :universal
|
70
|
+
else
|
71
|
+
ARCH = :unknown
|
72
|
+
end
|
73
|
+
SYSTEM = {}
|
74
|
+
|
75
|
+
# Figures up the system is running on a little or big endian processor
|
76
|
+
# architecture, and upates the SYSTEM[] hash in the Support module.
|
77
|
+
def self.determine_endianness
|
78
|
+
num = 0x12345678
|
79
|
+
native = [num].pack('l')
|
80
|
+
netunpack = native.unpack('N')[0]
|
81
|
+
if num == netunpack
|
82
|
+
SYSTEM[:endian] = :big
|
83
|
+
else
|
84
|
+
SYSTEM[:endian] = :little
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
determine_endianness
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
##################################################################
|
2
|
+
# Licensing Information #
|
3
|
+
# #
|
4
|
+
# The following code is licensed, as standalone code, under #
|
5
|
+
# the Ruby License, unless otherwise directed within the code. #
|
6
|
+
# #
|
7
|
+
# For information on the license of this code when distributed #
|
8
|
+
# with and used in conjunction with the other modules in the #
|
9
|
+
# Amp project, please see the root-level LICENSE file. #
|
10
|
+
# #
|
11
|
+
# © Michael J. Edgar and Ari Brown, 2009-2010 #
|
12
|
+
# #
|
13
|
+
##################################################################
|
14
|
+
|
15
|
+
module Amp
|
16
|
+
module Core
|
17
|
+
module Support
|
18
|
+
# This creates an opener that prepends a directory to all
|
19
|
+
# File opening, allowing repository formats to worry only
|
20
|
+
# about file paths relative to the repository root.
|
21
|
+
class RootedOpener
|
22
|
+
attr_reader :root
|
23
|
+
attr_accessor :create_mode
|
24
|
+
attr_accessor :default
|
25
|
+
|
26
|
+
alias_method :base, :root
|
27
|
+
|
28
|
+
##
|
29
|
+
# Creates a new opener with a root of +base+, and also set to open files in
|
30
|
+
# the .hg subdirectory. If you set .default = :open_file, it will no longer
|
31
|
+
# open files in the .hg subdir.
|
32
|
+
#
|
33
|
+
# @param [String] base the root directory of the repository this opener will be
|
34
|
+
# used on
|
35
|
+
def initialize(base)
|
36
|
+
@root = File.expand_path base
|
37
|
+
@create_mode = nil
|
38
|
+
@default = :open_hg
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Returns the path to the opener's root.
|
43
|
+
#
|
44
|
+
# @return path to the opener's root, as an absolute path.
|
45
|
+
def path
|
46
|
+
case @default
|
47
|
+
when :open_file
|
48
|
+
"#{root}/"
|
49
|
+
when :open_hg
|
50
|
+
"#{root}/.hg/"
|
51
|
+
when :open_git
|
52
|
+
"#{root}/.git"
|
53
|
+
else
|
54
|
+
raise abort "Unknown opener format #{@default.inspect}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Read the file passed in with mode 'r'.
|
60
|
+
# Synonymous with File.open(+file+, 'r') {|f| f.read } and
|
61
|
+
# File.read(+file+)
|
62
|
+
#
|
63
|
+
# @param [String] file the relative path to the file we're opening
|
64
|
+
# @return [String] the contents of the file
|
65
|
+
def read(file)
|
66
|
+
res = nil
|
67
|
+
open(file, 'r') {|f| res = f.read }
|
68
|
+
res
|
69
|
+
end
|
70
|
+
alias_method :contents, :read
|
71
|
+
|
72
|
+
##
|
73
|
+
# Opens up the given file, exactly like you would do with File.open.
|
74
|
+
# The parameters are the same. Defaults to opening a file in the .hg/
|
75
|
+
# folder, but if @default == :open_file, will open it from the working
|
76
|
+
# directory.
|
77
|
+
#
|
78
|
+
# If the mode includes write privileges, then the write will use an
|
79
|
+
# atomic temporary file.
|
80
|
+
#
|
81
|
+
# @param [String] file the path to the file to open
|
82
|
+
# @param [String] mode the read/write mode to open with (standard
|
83
|
+
# C choices here)
|
84
|
+
# @yield Can yield the opened file if the block form is used
|
85
|
+
def open(file, mode='r', &block)
|
86
|
+
if @default == :open_file
|
87
|
+
open_file file, mode, &block
|
88
|
+
else
|
89
|
+
open_hg file, mode, &block
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def join(file)
|
94
|
+
File.join(root, file)
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# Opens a file in the .hg repository using +@root+. This method
|
99
|
+
# operates atomically, and ensures that the file is always closed
|
100
|
+
# after use. The temporary files (while being atomically written)
|
101
|
+
# are stored in "#{@root}/.hg", and are deleted after use. If only
|
102
|
+
# a read is being done, it instead uses Kernel::open instead of
|
103
|
+
# File::amp_atomic_write.
|
104
|
+
#
|
105
|
+
# @param [String] file the file to open
|
106
|
+
# @param [String] mode the mode with which to open the file ("w", "r", "a", ...)
|
107
|
+
# @yield [file] code to run on the file
|
108
|
+
# @yieldparam [File] file the opened file
|
109
|
+
def open_hg(file, mode='w', &block)
|
110
|
+
open_up_file File.join(root, ".hg"), file, mode, &block
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# Opens a file in the repository (not in .hg).
|
115
|
+
# Writes are done atomically, and reads are efficiently
|
116
|
+
# done with Kernel::open. THIS IS NOT +open_up_file+!!!
|
117
|
+
#
|
118
|
+
# @param [String] file the file to open
|
119
|
+
# @param [String] mode the mode with which to open the file ("w", "r", "a", ...)
|
120
|
+
# @yield [file] code to run on the file
|
121
|
+
# @yieldparam [File] file the opened file
|
122
|
+
def open_file(file, mode='w', &block)
|
123
|
+
open_up_file root, file, mode, &block
|
124
|
+
end
|
125
|
+
|
126
|
+
##
|
127
|
+
# This does the actual opening of a file.
|
128
|
+
#
|
129
|
+
# @param [String] dir This dir is where the temp file is made, but ALSO
|
130
|
+
# the parent dir of +file+
|
131
|
+
# @param [String] file Just the file name. It must exist at "#{dir}/#{file}"
|
132
|
+
def open_up_file(dir, file, mode, &block)
|
133
|
+
path = File.join dir, file
|
134
|
+
if mode == 'r' # if we're doing a read, make this super snappy
|
135
|
+
Kernel::open path, mode, &block
|
136
|
+
else # we're doing a write
|
137
|
+
File::amp_atomic_write path, mode, @create_mode, dir, &block
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|