Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --jobs (parallel git fetch) #539

Merged
merged 14 commits into from
Mar 22, 2022
3 changes: 2 additions & 1 deletion docs/shards.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Exit status:
*init*::
Initializes a default _shard.yml_ in the current folder.

*install* [--frozen] [--without-development] [--production] [--skip-postinstall] [--skip-executables]::
*install* [--frozen] [--without-development] [--production] [--skip-postinstall] [--skip-executables] [--jobs=N]::
Resolves and installs dependencies into the _lib_ folder. If not already
present, generates a _shard.lock_ file from resolved dependencies, locking
version numbers or Git commits.
Expand All @@ -74,6 +74,7 @@ doesn't generate a conflict, thus generating a new _shard.lock_ file.
--production:: same as _--frozen_ and _--without-development_
--skip-postinstall:: Does not run postinstall of dependencies.
--skip-executables:: Does not install executables.
--jobs:: Number of repository downloads to perform in parallel (default: 8). Currently only for git.
--

*list* [--tree]::
Expand Down
1 change: 1 addition & 0 deletions src/cli.cr
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ module Shards
self.skip_executables = true
end
opts.on("--local", "Don't update remote repositories, use the local cache only.") { self.local = true }
opts.on("--jobs=N", "Number of repository downloads to perform in parallel (default: 8). Currently only for git.") { |n| self.jobs = n.to_i }
# TODO: remove in the future
opts.on("--ignore-crystal-version", "Has no effect. Kept for compatibility, to be removed in the future.") { }
opts.on("-v", "--verbose", "Increase the log verbosity, printing all debug statements.") { self.set_debug_log_level }
Expand Down
2 changes: 2 additions & 0 deletions src/config.cr
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,6 @@ module Shards
class_property? local = false
class_property? skip_postinstall = false
class_property? skip_executables = false

class_property jobs : Int32 = 8
end
34 changes: 34 additions & 0 deletions src/molinillo_solver.cr
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,39 @@ module Shards
end
end

private def prefetch_local_caches(deps)
return unless Shards.jobs > 1

count = 0
active = Atomic.new(0)
ch = Channel(Exception?).new(deps.size + 1)
deps.each do |dep|
count += 1
active.add(1)
while active.get > Shards.jobs
sleep 0.1
end
spawn do
begin
dep.resolver.update_local_cache if dep.resolver.is_a? GitResolver
ch.send(nil)
rescue ex : Exception
ch.send(ex)
ensure
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch!

active.sub(1)
end
end
end

count.times do
obj = ch.receive
raise obj if obj.is_a? Exception
m-o-e marked this conversation as resolved.
Show resolved Hide resolved
end
end

private def add_lock(base, lock_index, deps : Array(Dependency))
prefetch_local_caches(deps)

deps.each do |dep|
if lock = lock_index[dep.name]?
next unless dep.matches?(lock.version)
Expand All @@ -64,6 +96,8 @@ module Shards
end
deps = apply_overrides(deps)

prefetch_local_caches(deps)

base = Molinillo::DependencyGraph(Dependency, Dependency).new
if locks = @locks
lock_index = locks.to_h { |d| {d.name, d} }
Expand Down
2 changes: 1 addition & 1 deletion src/resolvers/fossil.cr
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ module Shards
end
end

private def update_local_cache
def update_local_cache
if cloned_repository? && origin_changed?
delete_repository
@updated_cache = false
Expand Down
14 changes: 7 additions & 7 deletions src/resolvers/git.cr
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ module Shards
end
end

private def update_local_cache
def update_local_cache
if cloned_repository? && origin_changed?
delete_repository
@updated_cache = false
Expand Down Expand Up @@ -317,7 +317,7 @@ module Shards
# This configuration can be overridden by defining the environment
# variable `GIT_ASKPASS`.
git_retry(err: "Failed to clone #{git_url}") do
run_in_current_folder "git clone -c core.askPass=true -c init.templateDir= --mirror --quiet -- #{Process.quote(git_url)} #{Process.quote(local_path)}"
run_in_folder "git clone -c core.askPass=true -c init.templateDir= --mirror --quiet -- #{Process.quote(git_url)} #{Process.quote(local_path)}"
end
end

Expand Down Expand Up @@ -411,12 +411,12 @@ module Shards
dependency_name = File.basename(path, ".git")
raise Error.new("Missing repository cache for #{dependency_name.inspect}. Please run without --local to fetch it.")
end
Dir.cd(path) do
run_in_current_folder(command, capture)
end
run_in_folder(command, path, capture)
end

private def run_in_current_folder(command, capture = false)
# Chdir to a folder and run command.
# Runs in current folder if `path` is nil.
private def run_in_folder(command, path : String? = nil, capture = false)
unless GitResolver.has_git_command?
raise Error.new("Error missing git command line tool. Please install Git first!")
end
Expand All @@ -425,7 +425,7 @@ module Shards

output = capture ? IO::Memory.new : Process::Redirect::Close
error = IO::Memory.new
status = Process.run(command, shell: true, output: output, error: error)
status = Process.run(command, shell: true, output: output, error: error, chdir: path)

if status.success?
output.to_s if capture
Expand Down
2 changes: 1 addition & 1 deletion src/resolvers/hg.cr
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ module Shards
end
end

private def update_local_cache
def update_local_cache
if cloned_repository? && origin_changed?
delete_repository
@updated_cache = false
Expand Down
3 changes: 3 additions & 0 deletions src/resolvers/resolver.cr
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ module Shards
abstract def install_sources(version : Version, install_dir : String)
abstract def report_version(version : Version) : String

def update_local_cache
end

def parse_requirement(params : Hash(String, String)) : Requirement
if version = params["version"]?
VersionReq.new version
Expand Down