Fabric: Vermeiden Sie optional die Verwendung von ssh, wenn Sie zu localhost wechseln

Erstellt am 19. Aug. 2011  ·  59Kommentare  ·  Quelle: fabric/fabric

Beschreibung

run()/sudo() würde intelligent erkennen, dass Sie zu localhost wechseln und stattdessen einfach local() ausführen. Dies wäre wahrscheinlich eine optionale Sache.

Kommentare von Jeff im IRC:

und ja, ich meine, es wird immer Overhead mit ssh vs. ) Ich bin mir nicht sicher, ob ich dieses halbmagische Verhalten im Kern haben möchte (auch wenn es standardmäßig deaktiviert ist und eine Option aktiviert ist, aber das würde helfen), aber trotzdem wäre es ein interessantes Experiment. und wenn es so einfach ist, wie ich denke, kann ich ehrlich gesagt keinen guten Grund dafür finden (wiederum vorausgesetzt, es ist nicht das Standardverhalten)

Ursprünglich eingereicht von Nick Welch ( mackstann ) am 11.11.2009 um 13:39 Uhr EST

Beziehungen

  • Dupliziert von #364: Ermöglichen Sie dem lokalen Betrieb, die SSH-Schicht zu umgehen
  • Bezogen auf #26: Implementieren Sie die Funktion "Trockenlauf"
Feature Network

Hilfreichster Kommentar

Wenn sich jemand fragt, "warum sollte das jemand tun?", lautet die Antwort, dass es bei einer Bereitstellungspipeline hilfreich sein kann, unabhängig von der Umgebung genau das gleiche Bereitstellungsskript auszuführen, anstatt ein spezielles Setup-Skript für localhost zu verwenden gegen alles andere.

Alle 59 Kommentare

James Pearson (xiong.chiamiov) schrieb:


Wie auch auf irc erwähnt, führe ich normalerweise keinen SSH-Server auf einem Desktop-Rechner aus, daher kann ich tatsächlich keine SSH-Verbindung zu localhost herstellen.


am 11.11.2009 um 15:13 Uhr EST

Travis Swicegood ( tswicegood ) hat gepostet:


Ich habe heute Abend etwas Ähnliches in Form einer neuen Fabric.operations-Funktion namens do implementiert. Es prüft env.run_as zu sehen, ob es gleich "lokal" ist, und wechselt dabei zur Methode local anstelle der Methode run (oder sudo wenn sudo=True als Kwarg übergeben wird). Es behandelt auch das Präfixieren lokaler Befehle mit sudo falls sie lokal ausgeführt werden.

Dies ist eine andere Art, dieses Problem zu umgehen, das funktioniert, ohne das Verhalten von run oder sudo zu ändern. Diese Änderungen sind in meinem Repository verfügbar.


am 2010-01-11 um 12:22 Uhr EST

Morgan Goose ( goosemo ) hat gepostet:


Ich finde das wirklich nicht plausibel. Was bringt es, als lokal zu laufen. Eine der Anforderungen von Fabric ist, dass sshd auf dem Computer, Remote oder Loopback ausgeführt wird. Das andere Problem ist, dass nur das Ändern von local put, get, rsync_project und andere nicht berücksichtigt, die alle noch ssh benötigen. Der Versuch, diese zu implementieren, würde nur wirklich mehr Probleme verursachen, da es jetzt im Bereich der Übersetzung von Fabfiles in Bash liegt.


am 13.03.2011 um 23:14 Uhr EDT

Jeff Forcer ( Bitprophet ) schrieb:


Obwohl ich auch nicht 100% davon überzeugt bin, dass dies eine großartige Idee ist, ist es eindeutig etwas, das eine Reihe von Benutzern für notwendig halten – eine weitere Anfrage wurde als Nr. 364 mit einer anderen Erklärung des Anwendungsfalls eingereicht.

Ich habe auch das Probelauf-Ticket in Bezug auf dieses hinzugefügt, weil (ich nehme an - wenn einer der anfordernden Benutzer dies überprüfen kann, wäre das großartig) der Hauptanwendungsfall für diese Funktion ist das Testen / Trocken- Laufen.


am 23.06.2011 um 11:26 Uhr EDT

Wie in #538 erwähnt, müssen wir, wenn wir jemals in der Lage sind, die drei Runner vollständig zu normalisieren, damit sie austauschbar verwendet werden können, sicherstellen, dass die Shell-Escape-Funktion konsistent über sie hinweg funktioniert. Im Moment verwenden wir kein Shell-Escape local , obwohl das zumindest teilweise daran liegt, dass es keinen Shell-Wrapper verwendet.

Wenn sich jemand fragt, "warum sollte das jemand tun?", lautet die Antwort, dass es bei einer Bereitstellungspipeline hilfreich sein kann, unabhängig von der Umgebung genau das gleiche Bereitstellungsskript auszuführen, anstatt ein spezielles Setup-Skript für localhost zu verwenden gegen alles andere.

+1 für die Funktion

+1

+10

+1

+1

Um Sie aufzuhalten, können Sie einfach sicherstellen, dass der OpenSSH-Server läuft. Führen Sie zuerst sudo apt-get install ssh , um sicherzustellen, dass Sie es installiert haben (auch wenn Sie denken, dass Sie es tun). Dann mach sudo service ssh start | stop | restart nach Bedarf. Aus diesem Thread gelernt .

+1

Mein Anwendungsfall ist einfach: Ich möchte dasselbe django-deploy-Skript verwenden, um ec2-Instanzen sowohl mit cloud-init über CloudWatch (der Fall für die Ausführung lokaler Befehle) als auch mit dem regulären fab deploy_django -H foo@bar zu konfigurieren.

+1

Dies wäre wirklich nützlich. Ein Anwendungsfall, den ich habe, ist die Verwendung von vagrant Shell Provisioner, um eine bestimmte VM mit Fabric zu konfigurieren, ohne dass localhost ssh benötigt wird.

+1

Ich war überrascht, das nicht schon in Fabric zu sehen.

Zu Ihrer Information: Die Implementierung dieser Funktion wird komplexer, wenn Sie an Fabric-Funktionen wie reboot() denken.

+1

Sollte schon Teil des Kerns sein!

+1

Es wäre durchaus sinnvoll: Aus abstrakter Sicht ist local nur ein Sonderfall von run , bei dem keine SSH-Maschinerie beteiligt ist.

Noch ein Hinweis (vielleicht offensichtlich): Fabric sollte schlau genug sein, um zu entscheiden, ob run nach dem Lesen von /etc/hosts in local umgewandelt werden soll.

Ich meine: wenn wir haben

env.host = [ 'mywebserver' ]

und in /etc/hosts haben wir:

127.0.0.1 mywebserver

dann sollten alle run Aufrufe eigentlich local Aufrufe sein.

Wenn wir dieses Konzept noch einen Schritt weiterführen, sollten wir run als lokalen Anruf behandeln, wenn der Remote-Host eine IP auflöst, die einer Netzwerkschnittstelle des lokalen Computers zugewiesen ist.
Z.B:
Fabfile:

env.host = [ 'mywebserver' ]

/etc/hosts:

192.168.1.1 mywebserver

ip addr :

[...]
eth0:
  inet 192.168.1.1
[...]

+1

+1 :+1:

:+1:

+1

+1

Fabric 2 verwendet pyinvoke/invoke, daher sollte dies dort ziemlich einfach sein. Ich würde auf Fabric 2 warten, um dies zu tun.

:+1:

+1

:+1:

:+1: Bitte implementieren Sie dies, insbesondere da Mac-Computer nicht automatisch so eingerichtet sind, dass SSH-Tunnel für den Remote-Zugriff auf den localhost-Server konfiguriert sind.

+1

+1 :)

+1 bitte

:+1:

:+1:

:+1:

Wir verwenden Fab zum Erstellen von Debian-Paketen und dies erhöht die Komplexität

Leute, hallo zusammen
Ich versuche, einen Stoffklon mit Unterschied zu erstellen:

  • Die Funktion run() funktioniert auf die gleiche Weise mit subprocess.popen unter localhost wie unter ssh connect to remote host
  • Factory verwendet openssh oder einen anderen SSH-Client (Sie sollten die Konfiguration dafür ändern), sodass Sie die gesamte Macht der SSH-Sockets nutzen können
  • Factory verwendet die gevent-Bibliothek für die asynchrone Ausführung

Sie können einen Blick darauf werfen, wenn Sie diese Funktion benötigen
https://github.com/Friz-zy/factory

Ich kann in dieser Diskussion etwas übersehen, aber hier ist, was ich getan habe, um denselben Code mit dem fabelhaften run Befehl sowohl auf localhost als auch auf Remote-Rechnern zu verwenden.

  1. Ich habe env.use_ssh_config = True in meiner fabfile.py eingestellt
  2. ssh-copy-id localhost

Dies löst Ihr Problem nicht, wenn Sie keinen SSH-Server auf Ihrem lokalen Computer ausführen

:+1:

+1

+1 Bitte implementieren Sie diese Funktion :)

+1

Könnte sehr nützlich sein, um Docker-Images mithilfe vorhandener Fabric-Skripts zu booten. Diese Funktion würde die Installation eines SSH-Servers auf dem Container vermeiden, was gegen die Best Practices von Docker verstößt

+1

+1

+1

Neben der Antwort von

# Generate new SSH key for local usage
ssh-keygen -f ~/.ssh/id_rsa -N ''

# Add server keys to users known hosts (eliminates 'are you sure' messages);
ssh-keyscan -H localhost > ~/.ssh/known_hosts

# Allow user to ssh to itself
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

Tatsächlich kann dies mithilfe von Küche getan werden. Sie müssen alle run Ausführungen so ändern, dass sie auf die cuisine.run Funktion verweisen, was einfach mit einem Import durchgeführt werden kann, und den Modus auf lokal ändern:

from cuisine import run, mode_local

mode_local()
print run("echo Hello")

Großartig @cgarciaarano

Für einfache Anwendungsfälle funktioniert das bei mir:

from fabric.api import run, local
# ...
# in task:
  if env.host is None or env.host == 'localhost':
    run = local

:+1:

Ich möchte, dass meine Fabfile remote oder lokal ausgeführt wird, wenn ssh keine Option ist. Dazu gehören lokale Wrapper für get/put/exists usw.

:+1: Ich habe Fabfiles, die sowohl lokal als auch remote laufen, und ich habe meine eigenen Wrapper-Funktionen für run/local/get gehackt, um mit all den subtilen Unterschieden wie Ausgabeerfassung und Fehlerbehandlung umzugehen.

Was ist, wenn Sie eine ssh-Verbindung haben, die dynamische Portweiterleitung und Bindung auf 127.0.0.2 (technisch immer noch localhost) auf Port 2223 durchführt. Ich kann sehen, wie dies zu Problemen führen kann, zu diesem Zweck auf localhost abzugleichen und auf 127.0.0.1 anstatt auch aufzulösen? Es könnte eine gute Idee sein, die gesamte Klasse 127.0.0.0/8 zu unterstützen.

@blade2005 Ja , der gesamte 127._._.*-Bereich zeigt auf Ihren localhost (außer 127.0.0.0 und 127.255.255.255), aber wenn Sie tatsächlich auf Ihren localhost zeigen, verwenden Sie nicht den Port, oder?
Ich glaube also, dass wir mit Sicherheit davon ausgehen können, dass 127.*.*.* == localhost und ssh vermieden werden können, aber 127.*.*.*:* auf einen weitergeleiteten Port zeigt und ssh benötigt wird.

Ehrlich gesagt, würde diese Funktion wahrscheinlich mehr Sinn machen als ein auf Fabric basierendes Drittanbieter-Plugin, ähnlich wie die Küchenbibliothek. Dann würden wir einfach verpackte Funktionen für run/get/put/etc importieren, die wissen, ob sie lokal oder remote basierend auf einer env-Variablen ausgeführt werden sollen. Auf diese Weise könnte zumindest jemand damit beginnen, damit jeder es verwenden kann.

Ich habe etwas lokal implementiert, und es ist viel mehr Arbeit, als nur zwischen lokal/ausgeführt zu wechseln. Sie müssen Präfixe, geänderte Verzeichnisse, Sudo-Benutzer usw. berücksichtigen.

Habe kurz im Zusammenhang mit einem anderen 2.0-bezogenen Ticket darüber nachgedacht und festgestellt, dass noch mehr auftaucht als nur " run wird zu einer erneuten Bindung von local ":

  • Jede Art von Aufgabe im wirklich gemischten Modus, die sowohl local als auch run oder eines von put / get , wird von Natur aus problematisch: Operationen mit klar definierten 'local' und 'remote' "enden" jetzt beide lokal.

    • Ich würde davon ausgehen , dass eine Minderheit Verwendung Fall zu sein (wenn es überhaupt eine gibt) , aber es muss noch herausgefunden werden, auch wenn es „eine Operation rief aber run oder sudo erhöht DoesntMakeAnySenseError " oder was auch immer.

    • put / get könnte sich vermutlich in shutil.copy oder ähnliches verwandeln

    • local würde vermutlich nicht geändert werden (obwohl beim Drucken, was passiert, wahrscheinlich immer noch unterschieden werden soll von dem, was run-except-locally vorangestellt ist...?)

    • Oben angesprochen, die verschiedenen kontext-manipulierenden Methoden/Kontextmanager wie prefix , cd usw. müssen alle ähnliche Fragen beantworten.

  • Abgesehen davon ist die lokale Ausführung von sudo Befehlen eine potenziell enorme Waffe und erfordert wahrscheinlich zusätzliche Sicherheitsüberprüfungen.

    • Es sei denn, es wird auch nur eine weitere Bindung an local , was eine andere Möglichkeit ist. Obwohl es kein großes ist, müssen alle sudo Befehle, die sogar lokal funktionieren (dh einer, der auf Linux verteilt und von Linux bereitgestellt wird), vermutlich lokal privilegiert bleiben (z. B. apt / yum und Freunde, Firewall-Tüftelei usw.).

  • sudo auch (wie oben von Jon erwähnt) die Möglichkeit erweitern, unterschiedliche lokale vs. entfernte Konfigurationsvektoren zu konfigurieren, da sich der sudo-Benutzer, das Passwort usw. zwischen den beiden Seiten wahrscheinlich unterscheiden.

    • Da ich jedoch an all dies im Kontext von Fab 2 denke, würden die erwarteten Konfigurationsüberschreibungen pro Host wahrscheinlich zumindest diesen Teil der Dinge lösen - dem Kontext localhost würden einfach die entsprechenden Werte übergeben. (Außerdem könnte sie als dedizierte "zum lokalen Ausführen von Remote-Dings" Context Unterklasse bei Bedarf auch andere Dinge tun).

@max-arnold hat dies in der v2-Alpha ausprobiert und stieß auf verwirrende Probleme, was zu diesem Zeitpunkt zu erwarten ist, da ich den Anwendungsfall dieses speziellen Tickets noch nicht erreicht hatte, außer dass ich run sicherstellte und local haben so ähnliche APIs wie möglich.

Im Moment ist das große Problem einfach die Art und API des Objekts, das an den Kontext einer Aufgabe gebunden ist ( c oder ctx oder wie auch immer man es nennt) posarg. Dies soll derzeit noch nicht endgültig sein, es ist bisher nur so ausgegangen:

  • Standardmäßig, wenn es von Executor von Invoke oder von FabExecutor von Fab 2 ausgeführt wird, wenn keine Hosts vorhanden sind, ist es invoke.Context , das ein run , das lokal ausgeführt wird , und es fehlt ein local ;
  • Wenn Fab 2 Host(s) zum Ausführen hat, erstellt es ein fabric.Connection , dessen run remote ausgeführt wird und dessen local eine Neubindung von run von Invoke ist.

Es sind spezifischere Überlegungen erforderlich, einschließlich der Betrachtung von Anwendungsfällen hier und in verknüpften Tickets. Brainstorming aus der Hand:

  • Eine nützliche Lösung (oder zumindest eine Dokumentation) dafür sollte fast definitiv im Kern vorhanden sein (gemäß einem früheren Chat darüber, dass er außerhalb des Kerns lebt), denn:

    • es ist ein häufig genug anwendungsfall

    • es ist leicht zu vermasseln

    • es ist erforderlich, um v2-kompatible Versionen von patchwork (geb. contrib ) und/oder invocations (Invokes Version davon) sinnvoll zu implementieren, insbesondere da es informiert, wie viel Code sie teilen können tun. Viele Tasks und/oder Subroutinen in diesen Arten von Codebasen möchten möglicherweise lokal oder remote ausgeführt werden.

  • Im Kern geht es darum, welche API von Kontextobjekten zu erwarten ist, bei denen die Aufgabe möglicherweise nicht genau weiß, "wie" sie aufgerufen wird
  • Könnte davon abhängen, wie die Aufgabe generiert wird, dh verschiedene Versionen von @task und/oder Kwargs dazu, wo der Benutzer seine Erwartungen angeben kann (dh "Ich möchte wirklich einen remotefähigen Kontext erhalten", "Bitte geben Sie mir niemals einen remotefähigen Kontext" usw.)

    • Vielleicht möchten wir dies _erfordern_, um Mehrdeutigkeiten zu vermeiden ( ZoP #12 )

    • Je mehr ich darüber nachdenke, desto klarer scheint es, dass wir wollen, dass Fabric seinen eigenen leichten Wrapper um @task / Task herum anbaut; pure-Invoke-Codebasen würden nur ihre @task was immer dazu führen würde, dass eine Vanilla Context , während Aufgaben, die über die Version von Fabric erstellt wurden, zumindest die Möglichkeit haben, eine Connection , falls nicht erforderlich.

    • Ein Nachteil ist der oben erwähnte Aufgabentyp "Ich kann lokal XOR aus der Ferne nützlich sein"; eine Aufgabe, die nur eine einzelne "Befehle bitte ausführen"-Option wünscht und nicht beide Modi gleichzeitig mischt. Dies _funktioniert_ nicht gut mit "Der Dekorator deklariert den Kontexttyp"-Lösungen, weil es _muss_, den Kontexttyp umzuschalten, je nachdem, wer ihn aufruft und wie.

    • Obwohl dies eigentlich ein ganzer Punkt der aktuellen API ist; diese Aufgaben sind _egal_ über die Kontextunterklasse, _solange ctx.run() existiert_.

    • Diese möchten also vermutlich mit der Version "Ich brauche nur eine Basis, Vanille-Kontext" von @task dekoriert werden, mit dem Verständnis, dass jemand von einem Fabric- (oder Fabric-ähnlichen) Aufruf-Standpunkt die Möglichkeit hat, diese zu geben Aufgaben a Connection statt Context .



      • Was uns zu der Frage zurückbringt, wie genau Aufgaben ausgeführt werden sollen, auch bekannt als pyinvoke/invoke#170



  • Unabhängig von der Implementierung müssen wir sicherstellen, dass wir das Potenzial von Schusswaffen in Bezug auf: Benutzer minimieren, die Folgendes tun:

    • local erwartet, wenn es nicht existiert (Fabric/Connection-erwartete Codeausführung über Invoke)

    • Es wird erwartet, dass run lokal ausgeführt wird, wenn einem stattdessen ein Kontext mit einem entfernten run zugewiesen wurde (Aufruf/Kontext-erwarteter Code wird über Fabric ausgeführt)

    • Alles andere aus Max' zusätzlichem Kommentar hier

  • Wie in viel älteren Kommentaren zu sehen ist, ist ein Unteranwendungsfall hier, dass Benutzer erwarten, dass das v2-Äquivalent von Connection('localhost').run('foo') _kein SSH verwendet_, sondern sich stattdessen genau wie Connection('localhost').local('foo') verhält.

    • Ich _schätze_, dass wir dies eigentlich nicht tun wollen, da es sich für jeden, der versucht, die Gesundheit der lokalen Hosts zu überprüfen, wie eine üble Schusswaffe anfühlt. Es fühlt sich für mich einfach zu magisch an. Aber ich bin offen für Argumente, wahrscheinlich auf Opt-in-Basis (zB setze eine Konfigurationsoption wie ssh.localhost_becomes_subprocess = True oder was auch immer.)

Mein einziger Anwendungsfall hier im Moment wäre, dass upload_template() eine Vorlage lokal rendern kann.

Natürlich könnte man es so machen:

#http://matthiaseisen.com/pp/patterns/p0198/
import os
import jinja2


def render(tpl_path, context):
    path, filename = os.path.split(tpl_path)
    return jinja2.Environment(
        loader=jinja2.FileSystemLoader(path or './')
    ).get_template(filename).render(context)

Aber warum nicht eine Option zum lokalen Rendern haben?

Der Hauptzweck dieser Funktion besteht in meinem Fall darin, die Anwendungskonfiguration für lokale Tests auf meinem lokalen Computer bereitzustellen.

Stellen Sie sich vor, Sie haben ein settings.py.j2 , das bei der Bereitstellung auf dem Zielserver gerendert wird, und dort heißt es settings.py und enthält nur Python-Code, kein Jinja.
Jetzt möchten Sie lokal testen, aber lokal gibt es noch kein settings.py , da es von settings.py.j2 gerendert werden muss.
Ihre App kann also nicht gestartet werden und Sie müssen für Ihre lokalen Tests manuell ein separates settings.py erstellen.

Das ist sehr anstrengend und sollte einfacher sein.

Zum Beispiel würde ich in Ansible der Aufgabe einfach mitteilen, dass sie "lokale Verbindung" verwenden wird, und sie würde auf dem lokalen Host rendern, ohne zu versuchen, per SSH darauf zuzugreifen.

Bis diese Funktion in Fabric verfügbar ist, verwende ich natürlich die oben eingefügte Lösung, da es sich nur um ein paar Codezeilen handelt. Es sollte aber imho einfacher sein. Ich glaube, das ist wirklich die Art von Stoff, die mir leicht gemacht werden sollte.

@fninja Ich habe upload_template selbst noch nicht portiert, aber ich stimme definitiv zu, dass es in diesen Problembereich fällt. Man könnte dies wohl handhaben, indem man einfach den Jinja-Wrapping-Renderschritt und den Upload-some-String-Upload-Schritt aufteilt, zumal letzterer bereits in Form von "hand a FLO to put " existiert. Z.B:

from StringIO import StringIO # too lazy to remember the newer path offhand
from somewhere.jinja_wrapper import render
from invoke import task

<strong i="9">@task</strong>
def render_settings(c):
    rendered = render('settings.py.j2', {'template': 'params'})
    c.put(StringIO(rendered), 'remote/path/to/settings.py')

Aber es gibt wahrscheinlich noch Platz für ein noch kürzeres 1-Stopp-Analogon zu upload_template , das entweder eine Connection Methode oder eine Subroutine mit einem Connection Argument wäre.

In jedem Fall wirft es weitere Fragen auf, wie genau diese Art von Dingen zu behandeln ist - zum Beispiel haben Context Objekte, die nur aufrufen, keine put / get . Lohnt es sich, sie hinzuzufügen? Es macht für Fabric-Benutzer im Kontext dieses Tickets viel Sinn (dann können upload_template oder wir können in beiden Fällen einfach put aufrufen), aber für reine Invoke-Benutzer ist es bizarr und nutzloser Teil der API.

+1, um dies zu einer Kernfunktion zu machen

Crosspost von #1637. Nur eine Idee:

from fabric import task, local

<strong i="6">@task</strong>
<strong i="7">@local</strong>
def build(ctx):
    with ctx.cd('/project/dir'):
        ctx.run('build > artifact.zip')

<strong i="8">@task</strong>
def deploy(conn):
    build(local(conn))

    with conn.cd('/remote/path'), local(conn).cd('/project/dir'):
        conn.put(remote_path='build.zip', local_path='artifact.zip')

Grundsätzlich kann local() als Dekorateur/Kontextmanager/Funktion fungieren und Connection in Context umwandeln.

Ein weiterer Anwendungsfall, von dem ich glaube, dass er nicht erwähnt wurde: Erstellen einer Bibliothek mit wiederverwendbaren Funktionen. In meinem Fall sind es hauptsächlich git Befehle. Ich habe ein zu einfaches dorun , das die Unterschiede zwischen den Funktionsparametern run und local verbirgt (in Version 1); welche Funktion gewählt wird, wird als Parameter übergeben. Hier ist zum Beispiel ein git checkout :

def git_checkout(branch, remote='origin', run=run):
    """Checkout a branch if necessary."""

    if branch == git_current_branch(run=run):
        return
    elif branch in git_local_branches(run=run):
        dorun('git checkout ' + branch, run=run)
    else:
        dorun('git checkout -t -b {0} {1}/{0}'.format(branch, remote), run=run)


def git_current_branch(run=run):
    """Get the current branch (aka HEAD)"""

    output = dorun('git name-rev --name-only HEAD', run=run)
    return output.strip()


def git_local_branches(run=run):
    """Get a list of local branches; assumes in repo directory."""

    output = dorun('git branch --no-color', run=run)
    branches = {l.strip().split(' ')[-1]
                for l in output.strip().split('\n')}
    return branches

Es sieht aus wie das:

from fabric.api import run as run_remote, local as run_local

def dorun(*args, **kwargs):
    """Work around the fact that "local" and "run" are very different."""
    kwargs.setdefault('run', run_remote)
    run = kwargs.pop('run')

    if run == run_local:
        kwargs.setdefault('capture', True)
    elif 'capture' in kwargs:
        del kwargs['capture']

    return run(*args, **kwargs)

Ich habe keine Ahnung, was mit sudo passiert, und es gibt Probleme, mit denen ich nicht so einfach umgehen kann, wie das Erweitern von ~remoteuser , um einen Pfad zu erzeugen.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen