Remove remaining deprecated contributed commands.
Moving them to homebrew-boneyard. Closes Homebrew/homebrew#28657.
This commit is contained in:
parent
9134718f9c
commit
cf41b57fe6
@ -1,186 +0,0 @@
|
||||
HOMEBREW_BEER = <<-EOS
|
||||
Recipe stolen from: http://allrecipes.com/howto/beer-brewing-for-beginners/
|
||||
|
||||
**The Key Ingredients**
|
||||
Before beginning the brewing process, you must first understand the four key
|
||||
ingredients necessary to brew a batch of beer: water, fermentable sugar, hops,
|
||||
and yeast. Each ingredient is integral to the recipe and must be cooked in a
|
||||
certain way to yield a successful batch of brew. Understanding their basic
|
||||
qualities and how each ingredient is meant to react with the others is an
|
||||
important aspect of beer brewing.
|
||||
|
||||
Water: Water is the primary ingredient in beer, so it is very important the
|
||||
water tastes good. If the tap water at your house tastes good to you, then it
|
||||
is fine to use for beer brewing. If you don't like the way your tap water
|
||||
tastes, then you can use bottled or distilled water instead. If you use tap
|
||||
water, boil it first to evaporate the chlorine and other chemicals that may
|
||||
interfere with the brewing process. Let the water cool before using.
|
||||
|
||||
Fermented Sugar: Malted barley is the ingredient commonly used to fill the
|
||||
sugar quota in a home brew recipe. Some brewers will substitute a percentage
|
||||
of corn, rice, wheat, or other grains to add a lighter flavor to the beer.
|
||||
Beginning brewers should purchase a ready-to-use form of malted barley called
|
||||
malt syrup or malt extract, rather than attempting to malt the grain from
|
||||
scratch, as it is a very complex and touchy process. Using a malt extract will
|
||||
guarantee the fermented sugar is prepared in just the right manner and will
|
||||
act as it needs to throughout the beer brewing process.
|
||||
|
||||
Hops: Hops are cone-like flowers found on a hop vine. They lend the bitter
|
||||
flavor to beer that balances out sweetness. Hops also inhibit spoilage and
|
||||
help keep the "head" (the frothy top when a beer is poured) around longer.
|
||||
|
||||
Yeast: First things first: Do not use bread yeast for beer brewing! Beer yeast
|
||||
is cultivated especially for use in brewing. There are two broad categories of
|
||||
beer yeast: ale and lager. Ale yeasts are top-fermenting, which means they
|
||||
tend to hang out at the top of the carboy while fermenting and rest at the
|
||||
bottom after the majority of fermenting has occurred. Ale yeasts will not
|
||||
actively ferment below 50 degrees F (20 degrees C). Lager yeasts are
|
||||
bottom-fermenters and are best used at a temperature ranging from 55 degrees F
|
||||
(25 degrees C) down to 32 degrees F (0 degrees C). As their names suggest, the
|
||||
type of yeast used plays an important part in influencing the type of beer
|
||||
that will be made. Do not rely on the yeast to define the beer, however, as
|
||||
all of the ingredients play a part in the taste and type of beer you will
|
||||
create.
|
||||
|
||||
**Ready to Brew?**
|
||||
We've opted to use a simple ale recipe to guide you through the process. The
|
||||
first cooking step in brewing is to make the wort, a soupy mixture of malt and
|
||||
sugar that is boiled before fermentation. Malt and sugar form the perfect food
|
||||
for yeast to grown in--thus making the all-important process of fermentation
|
||||
possible. All of the ingredients for beer-making can be found at your local
|
||||
brew supply store, or at any number of beer outfitters. Once you've got all
|
||||
the necessary equipment and ingredients, you're ready to begin the beer-making
|
||||
process by properly sanitizing your equipment, making and cooling the wort,
|
||||
fermenting the wort, and bottling your brew.
|
||||
|
||||
Ingredients:
|
||||
|
||||
1.5 gallons water
|
||||
6 pounds canned pre-hopped light malt syrup
|
||||
1 ounce hop pellets (choose your flavor)
|
||||
Ice poured into a water bath (do not use store-bought ice)
|
||||
3 gallons cool water
|
||||
2 (7-gram) packets ale yeast
|
||||
1 cup warm water (about 90 degrees F or 35 degrees C)
|
||||
3/4 cup liquid corn syrup (or 4 ounces dry corn syrup)
|
||||
1 (4-ounce) container iodine solution
|
||||
1 tablespoon bleach
|
||||
|
||||
A bottle of household bleach or an iodine solution that can be bought at your
|
||||
local home brew shop to sanitize all of your materials or use will be
|
||||
necessary. (Make a bleach disinfecting solution with 1 tablespoon bleach to 1
|
||||
gallon water.) Be sure to rinse the equipment well with boiling water before
|
||||
using it.
|
||||
|
||||
Part I: Make and Cool the Wort
|
||||
|
||||
Sanitize the pot, stirring spoon and fermenter with the sanitizing solution.
|
||||
Rinse everything in boiling water.
|
||||
|
||||
Bring 1.5 gallons of water to a boil. When the water begins to boil, remove it
|
||||
from the heat and stir in the malt syrup until it dissolves. Do not allow any
|
||||
syrup to stick to the bottom or sides of the pot, as it will burn and taste
|
||||
awful. Return the pot to the heat and bring the mixture to a boil for 50
|
||||
minutes, stir frequently and watch constantly to prevent boil-overs. If the
|
||||
mixture threatens to boil over, reduce the heat.
|
||||
|
||||
After 50 minutes have elapsed, stir in the hop pellets. Hops will create a
|
||||
foam on the top of the liquid--so if the pot is very full, the hops may cause
|
||||
a boil-over. You want to avoid this at all costs by lowering the heat or
|
||||
spraying the foam down with a water bottle (sanitized, of course). Let the
|
||||
hops cook for 10 to 20 minutes.
|
||||
|
||||
While the wort is being made, prep the yeast by placing 1 packet of yeast in 1
|
||||
cup of warm water (90 degrees F or 35 degrees C; stir and cover for 10
|
||||
minutes. If the yeast does not react (form foam), discard the yeast solution
|
||||
and try again with the second yeast packet.
|
||||
|
||||
At about the time hops are added to the wort, you should prepare an ice-cold
|
||||
water bath in either a large sink or tub to quick-cool the wort. Once the wort
|
||||
is finished cooking, float the pot in the water bath. Stir the wort while it
|
||||
is sitting in the bath so that the maximum amount of wort reaches the pot's
|
||||
sides where it can cool quickly. If the water bath heats up, add more ice to
|
||||
keep the water bath cold. It should take approximately 20 minutes to cool the
|
||||
wort to approximately 80 degrees F (27 degrees C).
|
||||
|
||||
|
||||
Part II: Ferment
|
||||
|
||||
Pour the 3 gallons cool water into your sanitized carboy. Funnel in the warm
|
||||
wort. Sprinkle the prepared yeast into the carboy. Cover the carboy's mouth
|
||||
with plastic wrap and cap it with a lid. Holding your hand tight over the lid,
|
||||
shake the bottle up and down to distribute the yeast. Remove the plastic wrap,
|
||||
wipe any wort around the carboy's mouth off and place the fermentation lock
|
||||
(with a little water added into its top) on.
|
||||
|
||||
Store the carboy in a cool (60 to 75 degrees F or 15 to 24 degrees C) safe
|
||||
place without direct sunlight where you will be able to easily clean up or
|
||||
drain any foam that escapes. A bathtub is an excellent place to store your
|
||||
fermenter if there are no windows in the room. If the temperature in the
|
||||
storage room drops and bubbling in the carboy's airlock stops, move the carboy
|
||||
to a warmer room. The fermenting will resume. Fermentation should begin within
|
||||
24 hours. A clear sign of fermentation is the production of foam and air
|
||||
bubbles in the fermentation lock.
|
||||
|
||||
When fermentation begins, it produces a slow trickle of bubbles that will
|
||||
increase in amount for a few days, and then reduce to a slow trickle again.
|
||||
Let the beer ferment for approximately 14 days when the primary fermentation
|
||||
has taken place. If the fermenting process pops the fermentation lock out of
|
||||
the carboy, re-sanitize it and place it back into the carboy.
|
||||
|
||||
|
||||
Part III: Bottle
|
||||
|
||||
Sanitize all of your bottles by soaking them in the sanitizing solution (make
|
||||
sure to hold them under the solution so the water gets inside of the bottles)
|
||||
for 1 hour. Rinse the bottles with boiling water. Also sanitize a small
|
||||
cooking pot, bottling bucket, siphon and racking cane. Follow the instructions
|
||||
that came with the bottle caps to sanitize them. Let everything air dry.
|
||||
Combine the corn syrup and 1 cup water in the sanitized cooking pot. Let boil
|
||||
10 minutes. Pour mixture into the bottling bucket. Be careful not to add too
|
||||
much corn syrup to the bottling bucket, because this will over-carbonate the
|
||||
beer and cause bottles to explode! Place the fermenter full of beer on the
|
||||
kitchen counter and the bottling bucket on the ground below it. Attach the
|
||||
racking cane to the siphon. Prepare the siphon by filling it with tap water.
|
||||
Pinch both ends of the siphon to prevent the water from running out. Place one
|
||||
end of the racking cane and siphon into the iodine solution and one end into
|
||||
an empty jar. When the solution has run into the siphon and expelled all of
|
||||
the water into the jar, pinch both ends and let the iodine sit in the siphon
|
||||
for 5 minutes to re-sanitize the siphon. (Resist the temptation to blow into
|
||||
the siphon with your mouth to encourage the flow of iodine solution.)
|
||||
|
||||
Place one end of the sanitized siphon into the fermenter and the other end
|
||||
into the jar; once the beer has begun flowing through the siphon, transfer its
|
||||
end to the bottling bucket. Monitor the speed that the beer transfers into the
|
||||
bottling bucket by pinching and releasing the siphon with your fingers (or use
|
||||
a specialty clamp). The beer should not splash into the bucket; it should
|
||||
gently rush into it. Once all of the beer has been siphoned into the bucket,
|
||||
cover it (with a sanitized cover ) and wait 30 minutes for the sediment to
|
||||
settle at the bottom of the bucket.
|
||||
|
||||
Place the bottling bucket on the counter, attach the siphon and run the other
|
||||
end of the siphon into a bottle. Fill each bottle with beer to 3/4 inch from
|
||||
the top of the bottle. Cap each bottle with the bottle-capper. Check and
|
||||
double-check that the caps are secure. Sure Signs of Infection:
|
||||
|
||||
Keep your eyes peeled for strands of slime in the beer and a milky layer at
|
||||
the top and/or residue bumps clinging to the air space in the bottleneck. If
|
||||
the beer has strands, it most likely has a lacto infection and should be
|
||||
discarded. The milky layer is a sign of a micro-derm infection; this beer
|
||||
should also be discarded.
|
||||
|
||||
Age the bottles at room temperature for up to two months, but for at least two
|
||||
weeks, before cracking one open, proposing a toast to yourself and impressing
|
||||
your friends! Ready to expand your brewing prowess?
|
||||
|
||||
Thanks for brewin'
|
||||
EOS
|
||||
|
||||
opoo <<-EOS.undent
|
||||
brew beer is deprecated and going to be removed at some point in the
|
||||
future. If you would like to volunteer to maintain it in a tap please get in
|
||||
contact with us. Thanks!
|
||||
|
||||
EOS
|
||||
|
||||
puts HOMEBREW_BEER
|
@ -1,86 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
# program name.
|
||||
NAME = "bundle-dir"
|
||||
|
||||
# defaults.
|
||||
PREFIX_DEFAULT = "~/.brews.d"
|
||||
|
||||
# effective prefix directory.
|
||||
PREFIX = File.expand_path(ENV["BUNDLE_DIR"] || PREFIX_DEFAULT)
|
||||
|
||||
# validate prefix directory exists and is readable.
|
||||
odie "'#{PREFIX}' does not exist, is not a directory, or is not readable." unless File.readable?(PREFIX) && File.directory?(PREFIX)
|
||||
|
||||
# list all available brewfiles in PREFIX.
|
||||
def list
|
||||
Dir["#{PREFIX}/**/*.brewfile"].select do |brewfile|
|
||||
File.readable?(brewfile)
|
||||
end
|
||||
end
|
||||
|
||||
# edit/open all available brewfiles in PREFIX.
|
||||
def edit
|
||||
odie "environment variable EDITOR is not set." unless ENV["EDITOR"].length > 0
|
||||
system "$EDITOR #{list().join(' ')}"
|
||||
end
|
||||
|
||||
# count number of `brew * install` lines across all found brewfiles.
|
||||
def count
|
||||
system "echo #{list().join(' ')} | xargs cat | grep -vE '^[#]' | grep -vE '^$' | wc -l | awk '{ print $NR }'"
|
||||
end
|
||||
|
||||
# print a usage message.
|
||||
def usage
|
||||
<<-USAGE
|
||||
Usage: brew #{NAME}
|
||||
|
||||
Options:
|
||||
|
||||
-c, --count Count of formula found in all brewfiles found in PREFIX.
|
||||
-e, --edit Edit/open all brewfiles found in PREFIX.
|
||||
-l, --list List all brewfiles found in PREFIX.
|
||||
-h, --help Display help information.
|
||||
USAGE
|
||||
end
|
||||
|
||||
opoo <<-EOS.undent
|
||||
brew bundle-dir is unsupported and will be removed soon.
|
||||
Please feel free volunteer to support it in a tap.
|
||||
|
||||
EOS
|
||||
|
||||
# command.
|
||||
command = ARGV.first
|
||||
|
||||
# help.
|
||||
if ["--help", "-h"].include? command
|
||||
puts usage ; exit 0
|
||||
end
|
||||
|
||||
# list.
|
||||
if ["--list", "-l"].include? command
|
||||
puts list ; exit 0
|
||||
end
|
||||
|
||||
# edit.
|
||||
if ["--edit", "-e"].include? command
|
||||
edit ; exit 0
|
||||
end
|
||||
|
||||
# count.
|
||||
if ["--count", "-c"].include? command
|
||||
count ; exit 0
|
||||
end
|
||||
|
||||
# unknown option.
|
||||
if !command.nil? && command.length > 0
|
||||
puts "#{usage}"
|
||||
puts "\n"
|
||||
odie "Unknown option: #{command}"
|
||||
end
|
||||
|
||||
# main.
|
||||
list().each do |brewfile|
|
||||
system "brew bundle #{brewfile}"
|
||||
end
|
@ -1,61 +0,0 @@
|
||||
# brew-bundle.rb
|
||||
|
||||
def usage
|
||||
puts <<-EOS.undent
|
||||
Usage: brew bundle [path]
|
||||
|
||||
Looks for a Brewfile and runs each line as a brew command.
|
||||
|
||||
brew bundle # Looks for "./Brewfile"
|
||||
brew bundle path/to/dir # Looks for "path/to/dir/Brewfile"
|
||||
brew bundle path/to/file # Looks for "path/to/file"
|
||||
|
||||
For example, given a Brewfile with the following content:
|
||||
install formula
|
||||
|
||||
Running `brew bundle` will run the command `brew install formula`.
|
||||
|
||||
NOTE: Not all brew commands will work consistently in a Brewfile.
|
||||
Some commands will raise errors which will stop execution of the Brewfile.
|
||||
|
||||
Example that outputs an error:
|
||||
tap my/tap # fails when my/tap has already been tapped
|
||||
|
||||
In this case use the full formula path in the Brewfile instead:
|
||||
install my/tap/formula # succeeds even when my/tap has already been tapped
|
||||
EOS
|
||||
exit
|
||||
end
|
||||
|
||||
opoo <<-EOS.undent
|
||||
brew bundle is unsupported and will be replaced with another,
|
||||
incompatible version at some point.
|
||||
Please feel free volunteer to support it in a tap.
|
||||
|
||||
EOS
|
||||
|
||||
usage if ARGV.include?('--help') || ARGV.include?('-h')
|
||||
|
||||
path = 'Brewfile'
|
||||
error = ' in current directory'
|
||||
|
||||
if ARGV.first
|
||||
if File.directory? ARGV.first
|
||||
path = "#{ARGV.first}/#{path}"
|
||||
error = " in '#{ARGV.first}'"
|
||||
else
|
||||
path = ARGV.first
|
||||
error = " at '#{ARGV.first}'"
|
||||
end
|
||||
end
|
||||
|
||||
raise "Cannot find Brewfile#{error}" unless File.exist? path
|
||||
|
||||
File.readlines(path).each_with_index do |line, index|
|
||||
command = line.chomp
|
||||
next if command.empty?
|
||||
next if command.chars.first == '#'
|
||||
|
||||
brew_cmd = "brew #{command}"
|
||||
odie "Command failed: L#{index+1}:#{brew_cmd}" unless system brew_cmd
|
||||
end
|
@ -1,369 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
$ brew install graphviz
|
||||
$ brew graph | dot -Tsvg -ohomebrew.html
|
||||
$ open homebrew.html
|
||||
"""
|
||||
from __future__ import with_statement
|
||||
from __future__ import print_function
|
||||
|
||||
from contextlib import contextmanager
|
||||
import re
|
||||
from subprocess import Popen, PIPE
|
||||
import sys
|
||||
|
||||
|
||||
def run(command, print_command=False):
|
||||
"Run a command, returning the exit code and output."
|
||||
if print_command: print(command)
|
||||
p = Popen(command, stdout=PIPE)
|
||||
output, errput = p.communicate()
|
||||
return p.returncode, output
|
||||
|
||||
|
||||
def _quote_id(id):
|
||||
return '"' + id.replace('"', '\"') + '"'
|
||||
|
||||
|
||||
def format_attribs(attrib):
|
||||
if len(attrib) == 0:
|
||||
return ''
|
||||
|
||||
values = ['%s="%s"' % (k, attrib[k]) for k in attrib]
|
||||
return '[' + ','.join(values) + ']'
|
||||
|
||||
|
||||
class Output(object):
|
||||
def __init__(self, fd=sys.stdout, tabstyle=" "):
|
||||
self.fd = fd
|
||||
self.tabstyle = tabstyle
|
||||
self.tablevel = 0
|
||||
|
||||
def close(self):
|
||||
self.fd = None
|
||||
|
||||
def out(self, s):
|
||||
self.tabout()
|
||||
self.fd.write(s)
|
||||
|
||||
def outln(self, s=None):
|
||||
if s is not None:
|
||||
self.tabout()
|
||||
self.fd.write(s)
|
||||
self.fd.write('\n')
|
||||
|
||||
@contextmanager
|
||||
def indented(self):
|
||||
self.indent()
|
||||
yield self
|
||||
self.dedent()
|
||||
|
||||
def indent(self):
|
||||
self.tablevel += 1
|
||||
|
||||
def dedent(self):
|
||||
if self.tablevel == 0:
|
||||
raise Exception('No existing indent level.')
|
||||
self.tablevel -= 1
|
||||
|
||||
def tabout(self):
|
||||
if self.tablevel:
|
||||
self.fd.write(self.tabstyle * self.tablevel)
|
||||
|
||||
|
||||
class NodeContainer(object):
|
||||
def __init__(self):
|
||||
self.nodes = list()
|
||||
self.node_defaults = dict()
|
||||
# Stack of node attribs
|
||||
self._node_styles = list()
|
||||
|
||||
def _node_style(self):
|
||||
if (len(self._node_styles) > 0):
|
||||
return self._node_styles[-1]
|
||||
else:
|
||||
return dict()
|
||||
|
||||
def _push_node_style(self, attrib):
|
||||
self._node_styles.append(attrib)
|
||||
|
||||
def _pop_node_style(self):
|
||||
return self._node_styles.pop()
|
||||
|
||||
@contextmanager
|
||||
def node_styles(self, attrib):
|
||||
self._push_node_style(attrib)
|
||||
yield
|
||||
self._pop_node_style()
|
||||
|
||||
def node(self, nodeid, label, attrib=None):
|
||||
_attrib = dict(self._node_style())
|
||||
if attrib is not None:
|
||||
_attrib.update(attrib)
|
||||
|
||||
n = Node(nodeid, label, _attrib)
|
||||
self.nodes.append(n)
|
||||
return n
|
||||
|
||||
def nodes_to_dot(self, out):
|
||||
if len(self.node_defaults) > 0:
|
||||
out.outln("node " + format_attribs(self.node_defaults) + ";")
|
||||
|
||||
if len(self.nodes) == 0:
|
||||
return
|
||||
|
||||
id_width = max([len(_quote_id(n.id)) for n in self.nodes])
|
||||
for node in self.nodes:
|
||||
node.to_dot(out, id_width)
|
||||
|
||||
|
||||
class Node(object):
|
||||
def __init__(self, nodeid, label, attrib=None):
|
||||
self.id = nodeid
|
||||
self.label = label
|
||||
self.attrib = attrib if attrib is not None else dict()
|
||||
|
||||
def as_dot(self, id_width=1):
|
||||
_attribs = dict(self.attrib)
|
||||
_attribs['label'] = self.label
|
||||
|
||||
return '%-*s %s' % (id_width, _quote_id(self.id), format_attribs(_attribs))
|
||||
|
||||
|
||||
def to_dot(self, out, id_width=1):
|
||||
out.outln(self.as_dot(id_width))
|
||||
|
||||
|
||||
class ClusterContainer(object):
|
||||
def __init__(self):
|
||||
self.clusters = list()
|
||||
|
||||
def cluster(self, clusterid, label, attrib=None):
|
||||
c = Cluster(clusterid, label, self, attrib)
|
||||
self.clusters.append(c)
|
||||
return c
|
||||
|
||||
|
||||
class Cluster(NodeContainer, ClusterContainer):
|
||||
def __init__(self, clusterid, label, parentcluster=None, attrib=None):
|
||||
NodeContainer.__init__(self)
|
||||
ClusterContainer.__init__(self)
|
||||
|
||||
self.id = clusterid
|
||||
self.label = label
|
||||
self.attrib = attrib if attrib is not None else dict()
|
||||
self.parentcluster = parentcluster
|
||||
|
||||
def cluster_id(self):
|
||||
return _quote_id("cluster_" + self.id)
|
||||
|
||||
def to_dot(self, out):
|
||||
out.outln("subgraph %s {" % self.cluster_id())
|
||||
with out.indented():
|
||||
# If the label is an HTML-like string (starts and end with '<' and '>', respectively),
|
||||
# don't put quotes around it (or GraphViz won't recognize it.)
|
||||
if self.label[0] == '<' and self.label[-1] == '>':
|
||||
out.outln('label = %s;' % self.label)
|
||||
else:
|
||||
out.outln('label = "%s"' % self.label)
|
||||
for k in self.attrib:
|
||||
if isinstance(self.attrib[k], dict):
|
||||
out.outln('%s %s;' % (k, format_attribs(self.attrib[k])))
|
||||
else:
|
||||
out.outln('%s = "%s";' % (k, self.attrib[k]))
|
||||
|
||||
for cluster in self.clusters:
|
||||
cluster.to_dot(out)
|
||||
|
||||
self.nodes_to_dot(out)
|
||||
out.outln("}")
|
||||
|
||||
|
||||
class Edge(object):
|
||||
def __init__(self, source, target, attrib=None):
|
||||
if attrib is None:
|
||||
attrib = dict()
|
||||
|
||||
self.source = source
|
||||
self.target = target
|
||||
self.attrib = attrib
|
||||
|
||||
def to_dot(self, out):
|
||||
out.outln(self.as_dot())
|
||||
|
||||
def as_dot(self):
|
||||
return " ".join((_quote_id(self.source), "->", _quote_id(self.target), format_attribs(self.attrib)))
|
||||
|
||||
|
||||
class EdgeContainer(object):
|
||||
def __init__(self):
|
||||
self.edges = list()
|
||||
self.edge_defaults = dict()
|
||||
# Stack of edge attribs
|
||||
self._edge_styles = list()
|
||||
|
||||
def _edge_style(self):
|
||||
if (len(self._edge_styles) > 0):
|
||||
return self._edge_styles[-1]
|
||||
else:
|
||||
return dict()
|
||||
|
||||
def _push_edge_style(self, attrib):
|
||||
self._edge_styles.append(attrib)
|
||||
|
||||
def _pop_edge_style(self):
|
||||
return self._edge_styles.pop()
|
||||
|
||||
@contextmanager
|
||||
def edge_styles(self, attrib):
|
||||
self._push_edge_style(attrib)
|
||||
yield
|
||||
self._pop_edge_style()
|
||||
|
||||
def link(self, source, target, attrib=None):
|
||||
_attrib = dict(self._edge_style())
|
||||
if attrib is not None:
|
||||
_attrib.update(attrib)
|
||||
|
||||
e = Edge(source, target, _attrib)
|
||||
self.edges.append(e)
|
||||
return e
|
||||
|
||||
def edges_to_dot(self, out):
|
||||
if len(self.edge_defaults) > 0:
|
||||
out.outln("edge " + format_attribs(self.edge_defaults) + ";")
|
||||
|
||||
if len(self.edges) == 0:
|
||||
return
|
||||
|
||||
for edge in self.edges:
|
||||
edge.to_dot(out)
|
||||
|
||||
|
||||
class Graph(NodeContainer, EdgeContainer, ClusterContainer):
|
||||
"""
|
||||
Contains the nodes, edges, and subgraph definitions for a graph to be
|
||||
turned into a Graphviz DOT file.
|
||||
"""
|
||||
|
||||
def __init__(self, label=None, attrib=None):
|
||||
NodeContainer.__init__(self)
|
||||
EdgeContainer.__init__(self)
|
||||
ClusterContainer.__init__(self)
|
||||
|
||||
self.label = label if label is not None else "Default Label"
|
||||
self.attrib = attrib if attrib is not None else dict()
|
||||
|
||||
def dot(self, fd=sys.stdout):
|
||||
try:
|
||||
self.o = Output(fd)
|
||||
self._dot()
|
||||
finally:
|
||||
self.o.close()
|
||||
|
||||
def _dot(self):
|
||||
self.o.outln("digraph G {")
|
||||
|
||||
with self.o.indented():
|
||||
self.o.outln('label = "%s"' % self.label)
|
||||
for k in self.attrib:
|
||||
# If the value of the attrib is a dictionary, write it out in special array form
|
||||
if isinstance(self.attrib[k], dict):
|
||||
self.o.outln('%s %s;' % (k, format_attribs(self.attrib[k])))
|
||||
else:
|
||||
self.o.outln('%s = "%s";' % (k, self.attrib[k]))
|
||||
|
||||
self.nodes_to_dot(self.o)
|
||||
|
||||
for cluster in self.clusters:
|
||||
self.o.outln()
|
||||
cluster.to_dot(self.o)
|
||||
|
||||
self.o.outln()
|
||||
self.edges_to_dot(self.o)
|
||||
|
||||
self.o.outln("}")
|
||||
|
||||
|
||||
def main():
|
||||
cmd = ["brew", "deps"]
|
||||
if sys.argv[1:]:
|
||||
if '--all' in sys.argv[1:]:
|
||||
show = 'all'
|
||||
cmd.extend(['--all'])
|
||||
else:
|
||||
show = 'one'
|
||||
hideOrphaned = False
|
||||
cmd.extend(sys.argv[1:])
|
||||
else:
|
||||
show = 'installed'
|
||||
cmd.extend(['--installed'])
|
||||
|
||||
code, output = run(cmd)
|
||||
output = output.strip()
|
||||
depgraph = list()
|
||||
|
||||
for f in output.split("\n"):
|
||||
stuff = f.split(":",2)
|
||||
if len(stuff) < 2:
|
||||
continue
|
||||
name = stuff[0]
|
||||
deps = stuff[1].strip()
|
||||
if not deps:
|
||||
deps = list()
|
||||
else:
|
||||
deps = deps.split(" ")
|
||||
depgraph.append((name, deps))
|
||||
|
||||
# We need newrank = True to make sure clusters respect rank = "source". Otherwise, we may get
|
||||
# random nodes next to "Safe to Remove" cluster, despite them not being a part of that cluster.
|
||||
hb = Graph("Homebrew Dependencies", attrib={
|
||||
'labelloc':'t', 'rankdir': 'TB' , 'ranksep':'3', 'newrank': True,
|
||||
'graph': {'fontname': 'Futura-Medium', 'fontsize': 48},
|
||||
'node': {'fontname': 'HelveticaNeue', 'fontsize': 14}
|
||||
})
|
||||
# Independent formulas (those that are not dependended on by any other formula) get placed in
|
||||
# their own subgraph so we can align them together on the left.
|
||||
if show == 'installed':
|
||||
# We use a HTML-like label to give the label a little bit of padding at the top
|
||||
sub = hb.cluster("independent", "<<font point-size=\"15\"><br/></font>Safe to Remove>",
|
||||
attrib={'rank': 'source', 'style': 'filled', 'fillcolor': '#F0F0F0', 'color': 'invis',
|
||||
'margin': '25,1', 'graph': {'fontname': 'Helvetica-LightOblique', 'fontsize': 24}})
|
||||
else:
|
||||
sub = hb
|
||||
|
||||
seen = set()
|
||||
def addNode(graph, name):
|
||||
if name not in seen:
|
||||
graph.node(name, name, attrib={'shape': 'box'})
|
||||
seen.add(name)
|
||||
return True
|
||||
return False
|
||||
|
||||
independent = set()
|
||||
for f in depgraph:
|
||||
# Filter out orphan formulas when showing all, to cut down on noise
|
||||
if show == 'all' and len(f[1]) == 0:
|
||||
continue
|
||||
|
||||
independent.add(f[0])
|
||||
for d in f[1]:
|
||||
independent.discard(d)
|
||||
hb.link(f[0], d)
|
||||
# Children we can add right away because we don't care where they go
|
||||
addNode(hb, d)
|
||||
|
||||
# For all installed formulas, place them in the 'indep' subgraph iff they
|
||||
# are not depended on by other formulas, i.e. are root nodes.
|
||||
for d in independent:
|
||||
addNode(sub, d)
|
||||
|
||||
hb.dot()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("""Warning: brew graph is unsupported and will be removed soon.
|
||||
You should use `brew deps --tree` instead.
|
||||
Please feel free volunteer to support it in a tap.
|
||||
""", file=sys.stderr)
|
||||
main()
|
@ -1,12 +0,0 @@
|
||||
begin
|
||||
require 'rubygems'
|
||||
require 'ruby-prof'
|
||||
rescue LoadError
|
||||
abort 'This command requires the ruby-prof gem'
|
||||
end
|
||||
|
||||
require 'formula'
|
||||
|
||||
RubyProf.start
|
||||
Formula.names.each { |n| Formula.factory(n) }
|
||||
RubyProf::GraphHtmlPrinter.new(RubyProf.stop).print(STDOUT)
|
@ -1,221 +0,0 @@
|
||||
#!/System/Library/Frameworks/Ruby.framework/Versions/Current/usr/bin/ruby
|
||||
|
||||
## brew server: Run a local webserver for browsing available and installed brews.
|
||||
# Note: this external command is ruby, but set up as a shell script, so that it gets exec'd.
|
||||
# This is required for sinatra's run-loop to take over.
|
||||
|
||||
$:.unshift(ENV['HOMEBREW_LIBRARY_PATH'])
|
||||
|
||||
require 'global'
|
||||
require 'formula'
|
||||
require 'cmd/search'
|
||||
|
||||
require 'rubygems'
|
||||
|
||||
opoo <<-EOS.undent
|
||||
brew server is unsupported and will be removed soon.
|
||||
You should use http://braumeister.org instead.
|
||||
Please feel free volunteer to support it in a tap.
|
||||
|
||||
EOS
|
||||
|
||||
begin
|
||||
require 'sinatra'
|
||||
rescue LoadError
|
||||
onoe 'Sinatra required but not found'
|
||||
puts 'To install: /usr/bin/gem install sinatra'
|
||||
exit 1
|
||||
end
|
||||
|
||||
require 'cgi'
|
||||
|
||||
def link_to_formula name
|
||||
"<a href=\"/formula/#{CGI.escape(name)}\">#{name}</a>"
|
||||
end
|
||||
|
||||
def css_style; <<-CSS
|
||||
<link href="/bootstrap.min.css" rel="stylesheet"/>
|
||||
<style>
|
||||
.container {
|
||||
text-align: center;
|
||||
}
|
||||
dl {
|
||||
text-align: left;
|
||||
width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
table.table {
|
||||
width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
</style>
|
||||
CSS
|
||||
end
|
||||
|
||||
def search_form; <<-EOS
|
||||
<form action="/search" class="form-search">
|
||||
<div class="input-append">
|
||||
<input id="search" name="q" type="text" class="input-large">
|
||||
<button class="btn btn-medium" type="submit"><i class="icon-search"></i> Search</button>
|
||||
</div>
|
||||
</form>
|
||||
EOS
|
||||
end
|
||||
|
||||
def html_page(title)
|
||||
body = <<-HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>#{title}</title>
|
||||
#{css_style}
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div id="header">
|
||||
<h1><a href="/">Homebrew</a></h1>
|
||||
<p id="subtitle" class="lead"><strong>The missing package manager for OS X</strong></p>
|
||||
</div>
|
||||
|
||||
<div id="informations">
|
||||
HTML
|
||||
|
||||
yield body
|
||||
|
||||
body << <<-HTML
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
body
|
||||
end
|
||||
|
||||
get '/' do
|
||||
html_page("Homebrew Menu") do |s|
|
||||
s << <<-HTML
|
||||
<div class="row">
|
||||
<div class="span12"><div class="row">#{search_form}</div></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span12"><p id="installed"><a class="btn btn-primary" href="/installed">Show installed packages</a></p></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<ul>
|
||||
HTML
|
||||
|
||||
Formula.names do |name|
|
||||
s << "<li>#{link_to_formula(name)}</li>"
|
||||
end
|
||||
|
||||
s << <<-HTML
|
||||
</ul>
|
||||
</div>
|
||||
HTML
|
||||
end
|
||||
end
|
||||
|
||||
get '/search' do
|
||||
q = params['q']
|
||||
results = Homebrew.search_formulae(q)
|
||||
|
||||
html_page("Results") do |s|
|
||||
s << <<-HTML
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<div class="row">#{search_form}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<div class="row"><h4>Searched for “#{q}”:</h4></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<div class="row"> <table class="table"><tr><th>Name</th></tr>
|
||||
HTML
|
||||
|
||||
results.each do |name|
|
||||
s << "<tr><td>#{link_to_formula(name)}</td></tr>"
|
||||
end
|
||||
|
||||
s << <<-HTML
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
HTML
|
||||
end
|
||||
end
|
||||
|
||||
get '/formula/:name' do
|
||||
f = Formula.factory(params[:name])
|
||||
|
||||
installed = <<-EOS
|
||||
<dt>Installed at</dt>
|
||||
<dd><a href=\"file://#{f.prefix}\">#{f.prefix}</a></dd>
|
||||
EOS
|
||||
|
||||
html_page("Formula: #{f.name}") do |s|
|
||||
s << <<-HTML
|
||||
<h1>#{f.name}</h1>
|
||||
<dl class="dl-horizontal">
|
||||
<dt>Version</dt>
|
||||
<dd>#{f.version}</dd>
|
||||
|
||||
<dt>Homepage</dt>
|
||||
<dd><a href="#{f.homepage}">#{f.homepage}</a></dd>
|
||||
|
||||
<dt>Download</dt>
|
||||
<dd><a href="#{f.url}">#{f.url}</a></dd>
|
||||
|
||||
#{installed if f.installed?}
|
||||
HTML
|
||||
|
||||
unless f.deps.empty?
|
||||
s << <<-HTML
|
||||
<dt>Depends on</td>
|
||||
HTML
|
||||
|
||||
f.deps.each do |dep|
|
||||
s << "<dd>#{link_to_formula(dep.name)}</dd>"
|
||||
end
|
||||
end
|
||||
|
||||
used_by = Formula.select { |ff| ff.deps.include?(f) }.map(&:name).flatten.uniq.sort
|
||||
|
||||
unless used_by.empty?
|
||||
s << <<-HTML
|
||||
<dt>Used by</td>
|
||||
HTML
|
||||
|
||||
used_by.each do |name|
|
||||
s << "<dd>#{link_to_formula(name)}</dd>"
|
||||
end
|
||||
end
|
||||
|
||||
s << <<-HTML
|
||||
</dl>
|
||||
HTML
|
||||
end
|
||||
end
|
||||
|
||||
get '/installed' do
|
||||
html_page("Installed Formulae") do |s|
|
||||
s << <<-HTML
|
||||
<h3>Installed Formulae:</h3>
|
||||
<table class="table"><tr><th>Name</th><th>Version</th></tr>
|
||||
HTML
|
||||
|
||||
Formula.installed.each do |f|
|
||||
s << "<tr><td>#{link_to_formula(f.name)}</td><td>#{f.version}</td></tr>"
|
||||
end
|
||||
|
||||
s << <<-HTML
|
||||
</table>
|
||||
HTML
|
||||
end
|
||||
end
|
||||
|
||||
puts "View our tasting menu at http://localhost:4567/\nUse \"Control-C\" to exit.\n\n"
|
@ -1,381 +0,0 @@
|
||||
#!/usr/bin/env ruby -w
|
||||
|
||||
# brew-services(1) - Easily start and stop formulae via launchctl
|
||||
# ===============================================================
|
||||
#
|
||||
# ## SYNOPSIS
|
||||
#
|
||||
# [<sudo>] `brew services` `list`<br>
|
||||
# [<sudo>] `brew services` `restart` <formula><br>
|
||||
# [<sudo>] `brew services` `start` <formula> [<plist>]<br>
|
||||
# [<sudo>] `brew services` `stop` <formula><br>
|
||||
# [<sudo>] `brew services` `cleanup`<br>
|
||||
#
|
||||
# ## DESCRIPTION
|
||||
#
|
||||
# Integrates homebrew formulae with MacOS X' `launchctl` manager. Services
|
||||
# can either be added to `/Library/LaunchDaemons` or `~/Library/LaunchAgents`.
|
||||
# Basically items added to `/Library/LaunchDaemons` are started at boot,
|
||||
# those in `~/Library/LaunchAgents` at login.
|
||||
#
|
||||
# When started with `sudo` it operates on `/Library/LaunchDaemons`, else
|
||||
# in the user space.
|
||||
#
|
||||
# Basically on `start` the plist file is generated and written to a `Tempfile`,
|
||||
# then copied to the launch path (existing plists are overwritten).
|
||||
#
|
||||
# ## OPTIONS
|
||||
#
|
||||
# To access everything quickly, some aliases have been added:
|
||||
#
|
||||
# * `rm`:
|
||||
# Shortcut for `cleanup`, because that's basically whats being done.
|
||||
#
|
||||
# * `ls`:
|
||||
# Because `list` is too much to type :)
|
||||
#
|
||||
# * `reload', 'r':
|
||||
# Alias for `restart`, which gracefully restarts selected service.
|
||||
#
|
||||
# * `load`, `s`:
|
||||
# Alias for `start`, guess what it does...
|
||||
#
|
||||
# * `unload`, `term`, `t`:
|
||||
# Alias for `stop`, stops and unloads selected service.
|
||||
#
|
||||
# ## SYNTAX
|
||||
#
|
||||
# Several existing formulae (like mysql, nginx) already write custom plist
|
||||
# files to the formulae prefix. Most of these implement `#startup_plist`
|
||||
# which then in turn returns a neat-o plist file as string.
|
||||
#
|
||||
# `brew services` operates on `#startup_plist` as well and requires
|
||||
# supporting formulae to implement it. This method should either string
|
||||
# containing the generated XML file, or return a `Pathname` instance which
|
||||
# points to a plist template, or a hash like:
|
||||
#
|
||||
# { :url => "https://gist.github.com/raw/534777/63c4698872aaef11fe6e6c0c5514f35fd1b1687b/nginx.plist.xml" }
|
||||
#
|
||||
# Some simple template parsing is performed, all variables like `{{name}}` are
|
||||
# replaced by basically doing:
|
||||
# `formula.send('name').to_s if formula.respond_to?('name')`, a bit like
|
||||
# mustache. So any variable in the `Formula` is available as template
|
||||
# variable, like `{{var}}`, `{{bin}}` usw.
|
||||
#
|
||||
# ## EXAMPLES
|
||||
#
|
||||
# Install and start service mysql at boot:
|
||||
#
|
||||
# $ brew install mysql
|
||||
# $ sudo brew services start mysql
|
||||
#
|
||||
# Stop service mysql (when launched at boot):
|
||||
#
|
||||
# $ sudo brew services stop mysql
|
||||
#
|
||||
# Start memcached at login:
|
||||
#
|
||||
# $ brew install memcached
|
||||
# $ brew services start memcached
|
||||
#
|
||||
# List all running services for current user, and root:
|
||||
#
|
||||
# $ brew services list
|
||||
# $ sudo brew services list
|
||||
#
|
||||
# ## BUGS
|
||||
#
|
||||
# `brew-services.rb` might not handle all edge cases, though it tries
|
||||
# to fix problems by running `brew services cleanup`.
|
||||
#
|
||||
module ServicesCli
|
||||
class << self
|
||||
# Binary name.
|
||||
def bin; "brew services" end
|
||||
|
||||
# Path to launchctl binary.
|
||||
def launchctl; which("launchctl") end
|
||||
|
||||
# Wohoo, we are root dude!
|
||||
def root?; Process.uid == 0 end
|
||||
|
||||
# Current user, i.e. owner of `HOMEBREW_CELLAR`.
|
||||
def user; @user ||= %x{/usr/bin/stat -f '%Su' #{HOMEBREW_CELLAR} 2>/dev/null}.chomp || %x{/usr/bin/whoami}.chomp end
|
||||
|
||||
# Run at boot.
|
||||
def boot_path; Pathname.new("/Library/LaunchDaemons") end
|
||||
|
||||
# Run at login.
|
||||
def user_path; Pathname.new(ENV['HOME'] + '/Library/LaunchAgents') end
|
||||
|
||||
# If root returns `boot_path` else `user_path`.
|
||||
def path; root? ? boot_path : user_path end
|
||||
|
||||
# Find all currently running services via launchctl list
|
||||
def running; %x{#{launchctl} list | grep homebrew.mxcl}.chomp.split("\n").map { |svc| $1 if svc =~ /(homebrew\.mxcl\..+)\z/ }.compact end
|
||||
|
||||
# Check if running as homebre and load required libraries et al.
|
||||
def homebrew!
|
||||
abort("Runtime error: homebrew is required, please start via `#{bin} ...`") unless defined?(HOMEBREW_LIBRARY_PATH)
|
||||
%w{fileutils pathname tempfile formula utils}.each { |req| require(req) }
|
||||
self.send(:extend, ::FileUtils)
|
||||
::Formula.send(:include, Service::PlistSupport)
|
||||
end
|
||||
|
||||
# Access current service
|
||||
def service; @service ||= Service.new(Formula.factory(@formula)) if @formula end
|
||||
|
||||
# Print usage and `exit(...)` with supplied exit code, if code
|
||||
# is set to `false`, then exit is ignored.
|
||||
def usage(code = 0)
|
||||
puts "usage: [sudo] #{bin} [--help] <command> [<formula>]"
|
||||
puts
|
||||
puts "Small wrapper around `launchctl` for supported formulae, commands available:"
|
||||
puts " cleanup Get rid of stale services and unused plists"
|
||||
puts " list List all services managed by `#{bin}`"
|
||||
puts " restart Gracefully restart selected service"
|
||||
puts " start Start selected service"
|
||||
puts " stop Stop selected service"
|
||||
puts
|
||||
puts "Options, sudo and paths:"
|
||||
puts
|
||||
puts " sudo When run as root, operates on #{boot_path} (run at boot!)"
|
||||
puts " Run at boot: #{boot_path}"
|
||||
puts " Run at login: #{user_path}"
|
||||
puts
|
||||
exit(code) unless code == false
|
||||
true
|
||||
end
|
||||
|
||||
# Run and start the command loop.
|
||||
def run!
|
||||
homebrew!
|
||||
usage if ARGV.empty? || ARGV.include?('help') || ARGV.include?('--help') || ARGV.include?('-h')
|
||||
|
||||
# parse arguments
|
||||
@args = ARGV.reject { |arg| arg[0] == 45 }.map { |arg| arg.include?("/") ? arg : arg.downcase } # 45.chr == '-'
|
||||
@cmd = @args.shift
|
||||
@formula = @args.shift
|
||||
|
||||
# dispatch commands and aliases
|
||||
case @cmd
|
||||
when 'cleanup', 'clean', 'cl', 'rm' then cleanup
|
||||
when 'list', 'ls' then list
|
||||
when 'restart', 'relaunch', 'reload', 'r' then check and restart
|
||||
when 'start', 'launch', 'load', 's', 'l' then check and start
|
||||
when 'stop', 'unload', 'terminate', 'term', 't', 'u' then check and stop
|
||||
else
|
||||
onoe "Unknown command `#{@cmd}`"
|
||||
usage(1)
|
||||
end
|
||||
end
|
||||
|
||||
# Check if formula has been found
|
||||
def check
|
||||
odie("Formula missing, please provide a formula name") unless service
|
||||
true
|
||||
end
|
||||
|
||||
# List all running services with PID and status and path to plist file, if available
|
||||
def list
|
||||
opoo("No %s services controlled by `#{bin}` running..." % [root? ? 'root' : 'user-space']) and return if running.empty?
|
||||
running.each do |label|
|
||||
if svc = Service.from(label)
|
||||
status = !svc.dest.file? ? "#{Tty.red}stale " : "#{Tty.white}started"
|
||||
puts "%-10.10s %s#{Tty.reset} %7s %s" % [svc.name, status, svc.pid ? svc.pid.to_s : '-', svc.dest.file? ? svc.dest : label]
|
||||
else
|
||||
puts "%-10.10s #{Tty.red}unknown#{Tty.reset} %7s #{label}" % ["?", "-"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Kill services without plist file and remove unused plists
|
||||
def cleanup
|
||||
cleaned = []
|
||||
|
||||
# 1. kill services which have no plist file
|
||||
running.each do |label|
|
||||
if svc = Service.from(label)
|
||||
if !svc.dest.file?
|
||||
puts "%-15.15s #{Tty.white}stale#{Tty.reset} => killing service..." % svc.name
|
||||
kill(svc)
|
||||
cleaned << label
|
||||
end
|
||||
else
|
||||
opoo "Service #{label} not managed by `#{bin}` => skipping"
|
||||
end
|
||||
end
|
||||
|
||||
# 2. remove unused plist files
|
||||
Dir[path + 'homebrew.mxcl.*.plist'].each do |file|
|
||||
unless running.include?(File.basename(file).sub(/\.plist$/i, ''))
|
||||
puts "Removing unused plist #{file}"
|
||||
rm file
|
||||
cleaned << file
|
||||
end
|
||||
end
|
||||
|
||||
puts "All #{root? ? 'root' : 'user-space'} services OK, nothing cleaned..." if cleaned.empty?
|
||||
end
|
||||
|
||||
# Stop if loaded, then start again
|
||||
def restart
|
||||
stop if service.loaded?
|
||||
start
|
||||
end
|
||||
|
||||
# Start a service
|
||||
def start
|
||||
odie "Service `#{service.name}` already started, use `#{bin} restart #{service.name}`" if service.loaded?
|
||||
|
||||
custom_plist = @args.first
|
||||
if custom_plist
|
||||
if custom_plist =~ %r{\Ahttps?://.+}
|
||||
custom_plist = { :url => custom_plist }
|
||||
elsif File.exist?(custom_plist)
|
||||
custom_plist = Pathname.new(custom_plist)
|
||||
else
|
||||
odie "#{custom_plist} is not a url or exising file"
|
||||
end
|
||||
end
|
||||
|
||||
odie "Formula `#{service.name}` not installed, #startup_plist not implemented or no plist file found" if !custom_plist && !service.plist?
|
||||
|
||||
temp = Tempfile.new(service.label)
|
||||
temp << service.generate_plist(custom_plist)
|
||||
temp.flush
|
||||
|
||||
rm service.dest if service.dest.exist?
|
||||
service.dest_dir.mkpath unless service.dest_dir.directory?
|
||||
cp temp.path, service.dest
|
||||
|
||||
# clear tempfile
|
||||
temp.close
|
||||
|
||||
safe_system launchctl, "load", "-w", service.dest.to_s
|
||||
$?.to_i != 0 ? odie("Failed to start `#{service.name}`") : ohai("Successfully started `#{service.name}` (label: #{service.label})")
|
||||
end
|
||||
|
||||
# Stop a service or kill if no plist file available...
|
||||
def stop
|
||||
unless service.loaded?
|
||||
rm service.dest if service.dest.exist? # get rid of installed plist anyway, dude
|
||||
odie "Service `#{service.name}` not running, wanna start it? Try `#{bin} start #{service.name}`"
|
||||
end
|
||||
|
||||
if service.dest.exist?
|
||||
puts "Stopping `#{service.name}`... (might take a while)"
|
||||
safe_system launchctl, "unload", "-w", service.dest.to_s
|
||||
$?.to_i != 0 ? odie("Failed to stop `#{service.name}`") : ohai("Successfully stopped `#{service.name}` (label: #{service.label})")
|
||||
else
|
||||
puts "Stopping stale service `#{service.name}`... (might take a while)"
|
||||
kill(service)
|
||||
end
|
||||
rm service.dest if service.dest.exist?
|
||||
end
|
||||
|
||||
# Kill service without plist file by issuing a `launchctl remove` command
|
||||
def kill(svc)
|
||||
safe_system launchctl, "remove", svc.label
|
||||
odie("Failed to remove `#{svc.name}`, try again?") unless $?.to_i == 0
|
||||
while svc.loaded?
|
||||
puts " ...checking status"
|
||||
sleep(5)
|
||||
end
|
||||
ohai "Successfully stopped `#{svc.name}` via #{svc.label}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Wrapper for a formula to handle service related stuff like parsing
|
||||
# and generating the plist file.
|
||||
class Service
|
||||
|
||||
# Support module which will be used to extend Formula with a method :)
|
||||
module PlistSupport
|
||||
# As a replacement value for `<key>UserName</key>`.
|
||||
def startup_user; ServicesCli.user end
|
||||
end
|
||||
|
||||
# Access the `Formula` instance
|
||||
attr_reader :formula
|
||||
|
||||
# Create a new `Service` instance from either a path or label.
|
||||
def self.from(path_or_label)
|
||||
return nil unless path_or_label =~ /homebrew\.mxcl\.([^\.]+)(\.plist)?\z/
|
||||
new(Formula.factory($1)) rescue nil
|
||||
end
|
||||
|
||||
# Initialize new `Service` instance with supplied formula.
|
||||
def initialize(formula); @formula = formula end
|
||||
|
||||
# Delegate access to `formula.name`.
|
||||
def name; @name ||= formula.name end
|
||||
|
||||
# Label delegates to formula.plist_name, e.g `homebrew.mxcl.<formula>`.
|
||||
def label; @label ||= formula.plist_name end
|
||||
|
||||
# Path to a static plist file, this is always `homebrew.mxcl.<formula>.plist`.
|
||||
def plist; @plist ||= formula.prefix + "#{label}.plist" end
|
||||
|
||||
# Path to destination plist directory, if run as root it's `boot_path`, else `user_path`.
|
||||
def dest_dir; (ServicesCli.root? ? ServicesCli.boot_path : ServicesCli.user_path) end
|
||||
|
||||
# Path to destination plist, if run as root it's in `boot_path`, else `user_path`.
|
||||
def dest; dest_dir + "#{label}.plist" end
|
||||
|
||||
# Returns `true` if formula implements #startup_plist or file exists.
|
||||
def plist?; formula.installed? && (plist.file? || formula.respond_to?(:startup_plist)) end
|
||||
|
||||
# Returns `true` if service is loaded, else false.
|
||||
def loaded?; %x{#{ServicesCli.launchctl} list | grep #{label} 2>/dev/null}.chomp =~ /#{label}\z/ end
|
||||
|
||||
# Get current PID of daemon process from launchctl.
|
||||
def pid
|
||||
status = %x{#{ServicesCli.launchctl} list | grep #{label} 2>/dev/null}.chomp
|
||||
return $1.to_i if status =~ /\A([\d]+)\s+.+#{label}\z/
|
||||
end
|
||||
|
||||
# Generate that plist file, dude.
|
||||
def generate_plist(data = nil)
|
||||
data ||= plist.file? ? plist : formula.startup_plist
|
||||
|
||||
if data.respond_to?(:file?) && data.file?
|
||||
data = data.read
|
||||
elsif data.respond_to?(:keys) && data.keys.include?(:url)
|
||||
require 'open-uri'
|
||||
data = open(data).read
|
||||
end
|
||||
|
||||
# replace "template" variables and ensure label is always, always homebrew.mxcl.<formula>
|
||||
data = data.to_s.gsub(/\{\{([a-z][a-z0-9_]*)\}\}/i) { |m| formula.send($1).to_s if formula.respond_to?($1) }.
|
||||
gsub(%r{(<key>Label</key>\s*<string>)[^<]*(</string>)}, '\1' + label + '\2')
|
||||
|
||||
# and force fix UserName, if necessary
|
||||
if formula.startup_user != "root" && data =~ %r{<key>UserName</key>\s*<string>root</string>}
|
||||
data = data.gsub(%r{(<key>UserName</key>\s*<string>)[^<]*(</string>)}, '\1' + formula.startup_user + '\2')
|
||||
elsif ServicesCli.root? && formula.startup_user != "root" && data !~ %r{<key>UserName</key>}
|
||||
data = data.gsub(%r{(</dict>\s*</plist>)}, " <key>UserName</key><string>#{formula.startup_user}</string>\n\\1")
|
||||
end
|
||||
|
||||
if ARGV.verbose?
|
||||
ohai "Generated plist for #{formula.name}:"
|
||||
puts " " + data.gsub("\n", "\n ")
|
||||
puts
|
||||
end
|
||||
|
||||
data
|
||||
end
|
||||
end
|
||||
|
||||
# Start the cli dispatch stuff.
|
||||
#
|
||||
|
||||
opoo <<-EOS.undent
|
||||
brew services is unsupported and will be removed soon.
|
||||
You should use launchctl instead.
|
||||
Please feel free volunteer to support it in a tap.
|
||||
|
||||
EOS
|
||||
|
||||
ServicesCli.run!
|
@ -1,19 +0,0 @@
|
||||
require "formula_versions"
|
||||
|
||||
raise "Please `brew update` first" unless (HOMEBREW_REPOSITORY/".git").directory?
|
||||
raise FormulaUnspecifiedError if ARGV.named.empty?
|
||||
|
||||
opoo <<-EOS.undent
|
||||
brew-versions is unsupported and will be removed soon.
|
||||
You should use the homebrew-versions tap instead:
|
||||
https://github.com/Homebrew/homebrew-versions
|
||||
|
||||
EOS
|
||||
ARGV.formulae.each do |f|
|
||||
versions = FormulaVersions.new(f)
|
||||
path = versions.repository_path
|
||||
versions.each do |version, rev|
|
||||
print "#{Tty.white}#{version.to_s.ljust(8)}#{Tty.reset} "
|
||||
puts "git checkout #{rev} #{path}"
|
||||
end
|
||||
end
|
@ -1,55 +0,0 @@
|
||||
require 'extend/pathname'
|
||||
|
||||
module Homebrew
|
||||
def which_versions which_brews=nil
|
||||
opoo <<-EOS.undent
|
||||
brew which is unsupported and will be removed soon.
|
||||
|
||||
You should use `brew list --versions` instead.
|
||||
To query other formula information see:
|
||||
https://github.com/Homebrew/homebrew/wiki/Querying-Brew
|
||||
|
||||
Please feel free volunteer to support it in a tap.
|
||||
|
||||
EOS
|
||||
|
||||
brew_links = Array.new
|
||||
version_map = Hash.new
|
||||
|
||||
real_cellar = HOMEBREW_CELLAR.realpath
|
||||
|
||||
(HOMEBREW_PREFIX/'opt').subdirs.each do |path|
|
||||
next unless path.symlink? && path.resolved_path_exists?
|
||||
brew_links << Pathname.new(path.realpath)
|
||||
end
|
||||
|
||||
brew_links = brew_links.collect{|p|p.relative_path_from(real_cellar).to_s}.reject{|p|p.start_with?("../")}
|
||||
|
||||
brew_links.each do |p|
|
||||
parts = p.split("/")
|
||||
next if parts.count < 2 # Shouldn't happen for normally installed brews
|
||||
brew = parts.shift
|
||||
version = parts.shift
|
||||
|
||||
next unless which_brews.include? brew if which_brews
|
||||
|
||||
versions = version_map[brew] || []
|
||||
versions << version unless versions.include? version
|
||||
version_map[brew] = versions
|
||||
end
|
||||
|
||||
return version_map
|
||||
end
|
||||
|
||||
def which
|
||||
which_brews = ARGV.named.empty? ? nil : ARGV.named
|
||||
|
||||
brews = which_versions which_brews
|
||||
brews.keys.sort.each do |b|
|
||||
puts "#{b}: #{brews[b].sort*' '}"
|
||||
end
|
||||
puts
|
||||
end
|
||||
end
|
||||
|
||||
Homebrew.which
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 8.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 12 KiB |
Loading…
x
Reference in New Issue
Block a user