amp-core 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|