on master help sign in
Merge branch 'master' into overridable-static
c67fe87Luigy Leon
default.nix+107−113
@@ -1,20 +1,13 @@
1{ system ? builtins.currentSystem
1{ system ? builtins.currentSystem
2, profiling ? false
2, profiling ? false
3, iosSdkVersion ? "10.2"
3, iosSdkVersion ? "10.2"
4+, __useLegacyCompilers ? false
4}:
5}:
5let
6let
6− getReflexPlatform = sys: import ./dep/reflex-platform { inherit iosSdkVersion; system = sys; };
7+ cleanSource = builtins.filterSource (name: _: let baseName = builtins.baseNameOf name; in !(
7− reflex-platform = getReflexPlatform system;
8+ builtins.match "^\\.ghc\\.environment.*" baseName != null ||
8− inherit (reflex-platform) hackGet nixpkgs;
9+ baseName == "cabal.project.local"
9− pkgs = nixpkgs;
10+ ));
10−in with pkgs.haskell.lib; with pkgs.lib;
11−let
12− # TODO: Remove this after updating nixpkgs: https://github.com/NixOS/nixpkgs/issues/37750
13− justStaticExecutables' = drv: let
14− drv' = justStaticExecutables drv;
15− in if pkgs.stdenv.isDarwin
16− then removeConfigureFlag drv' "--ghc-option=-optl=-dead_strip"
17− else drv';
18
11
19 commandRuntimeDeps = pkgs: with pkgs; [
12 commandRuntimeDeps = pkgs: with pkgs; [
20 coreutils
13 coreutils
@@ -24,103 +17,108 @@ let
24 openssh
17 openssh
25 ];
18 ];
26
19
27− #TODO: Upstream
20+ getReflexPlatform = getReflexPlatform' __useLegacyCompilers;
28− # Modify a Haskell package to add completion scripts for the given
21+ getReflexPlatform' = __useLegacyCompilers: sys: import ./dep/reflex-platform {
29− # executable produced by it. These completion scripts will be picked up
22+ inherit iosSdkVersion __useLegacyCompilers;
30− # automatically if the resulting derivation is installed, e.g. by
23+ system = sys;
31− # `nix-env -i`.
24+ enableLibraryProfiling = profiling;
32− addOptparseApplicativeCompletionScripts = exeName: pkg: overrideCabal pkg (drv: {
33− postInstall = (drv.postInstall or "") + ''
34− BASH_COMP_DIR="$out/share/bash-completion/completions"
35− mkdir -p "$BASH_COMP_DIR"
36− "$out/bin/${exeName}" --bash-completion-script "$out/bin/${exeName}" >"$BASH_COMP_DIR/ob"
37
25
38− ZSH_COMP_DIR="$out/share/zsh/vendor-completions"
26+ nixpkgsOverlays = [
39− mkdir -p "$ZSH_COMP_DIR"
27+ (self: super: {
40− "$out/bin/${exeName}" --zsh-completion-script "$out/bin/${exeName}" >"$ZSH_COMP_DIR/_ob"
28+ obeliskExecutableConfig = import ./lib/executable-config { nixpkgs = pkgs; filterGitSource = cleanSource; };
29+ })
30+ ];
41
31
42− FISH_COMP_DIR="$out/share/fish/vendor_completions.d"
32+ haskellOverlays = [
43− mkdir -p "$FISH_COMP_DIR"
44− "$out/bin/${exeName}" --fish-completion-script "$out/bin/${exeName}" >"$FISH_COMP_DIR/ob.fish"
45− '';
46− });
47
33
48− # The haskell environment used to build Obelisk itself, e.g. the 'ob' command
34+ # Fix misc upstream packages
49− ghcObelisk = reflex-platform.ghc.override {
35+ (self: super: let
50− overrides = composeExtensions defaultHaskellOverrides (self: super: {
36+ pkgs = self.callPackage ({ pkgs }: pkgs) {};
51− mkDerivation = args: super.mkDerivation (args // {
37+ in {
52− enableLibraryProfiling = profiling;
38+ # Need deriveSomeUniverse
39+ # PR: https://github.com/dmwit/universe/pull/32
40+ universe-template = self.callCabal2nix "universe-template" (pkgs.fetchFromGitHub {
41+ owner = "obsidiansystems";
42+ repo = "universe";
43+ rev = "5a2fc823caa4163411d7e41aa80e67cefb15944a";
44+ sha256 = "0ll2z0fh18z6x8jl8kbp7ldagwccz3wjmvrw1gw752z058n82yfa";
45+ } + /template) {};
46+ })
47+
48+ # Add obelisk packages
49+ (self: super: let
50+ pkgs = self.callPackage ({ pkgs }: pkgs) {};
51+ in {
52+ obelisk-asset-manifest = self.callCabal2nix "obelisk-asset-manifest" (hackGet ./lib/asset + "/manifest") {};
53+ obelisk-asset-serve-snap = self.callCabal2nix "obelisk-asset-serve-snap" (hackGet ./lib/asset + "/serve-snap") {};
54+ obelisk-backend = self.callCabal2nix "obelisk-backend" (cleanSource ./lib/backend) {};
55+ obelisk-cliapp = self.callCabal2nix "obelisk-cliapp" (cleanSource ./lib/cliapp) {};
56+ obelisk-command = (self.callCabal2nix "obelisk-command" (cleanSource ./lib/command) {}).overrideAttrs
57+ (drv: {
58+ buildInputs = drv.buildInputs ++ [ pkgs.makeWrapper ];
59+ postFixup = ''
60+ ${drv.postFixup or ""}
61+ # Make `ob` reference its runtime dependencies.
62+ wrapProgram "$out"/bin/ob --prefix PATH : ${pkgs.lib.makeBinPath (commandRuntimeDeps pkgs)}
63+ '';
64+ });
65+ obelisk-executable-config = pkgs.obeliskExecutableConfig.haskellPackage self;
66+ obelisk-executable-config-inject = pkgs.obeliskExecutableConfig.platforms.web.inject self;
67+ obelisk-frontend = self.callCabal2nix "obelisk-frontend" (cleanSource ./lib/frontend) {};
68+ obelisk-run = self.callCabal2nix "obelisk-run" (cleanSource ./lib/run) {};
69+ obelisk-route = self.callCabal2nix "obelisk-route" (cleanSource ./lib/route) {};
70+ obelisk-selftest = self.callCabal2nix "obelisk-selftest" (cleanSource ./lib/selftest) {};
71+ obelisk-snap = self.callCabal2nix "obelisk-snap" (cleanSource ./lib/snap) {};
72+ obelisk-snap-extras = self.callCabal2nix "obelisk-snap-extras" (cleanSource ./lib/snap-extras) {};
53− });
73+ })
54
74
55 # Dynamic linking with split objects dramatically increases startup time (about 0.5 seconds on a decent machine with SSD)
75 # Dynamic linking with split objects dramatically increases startup time (about 0.5 seconds on a decent machine with SSD)
56− obelisk-command = addOptparseApplicativeCompletionScripts "ob" (justStaticExecutables' super.obelisk-command);
76+ (self: super: let
57− });
77+ pkgs = self.callPackage ({ pkgs }: pkgs) {};
58− };
78+ haskellLib = pkgs.haskell.lib;
79+ #TODO: Upstream
80+ # Modify a Haskell package to add completion scripts for the given
81+ # executable produced by it. These completion scripts will be picked up
82+ # automatically if the resulting derivation is installed, e.g. by
83+ # `nix-env -i`.
84+ addOptparseApplicativeCompletionScripts = exeName: pkg: haskellLib.overrideCabal pkg (drv: {
85+ postInstall = (drv.postInstall or "") + ''
86+ BASH_COMP_DIR="$out/share/bash-completion/completions"
87+ mkdir -p "$BASH_COMP_DIR"
88+ "$out/bin/${exeName}" --bash-completion-script "$out/bin/${exeName}" >"$BASH_COMP_DIR/ob"
59
89
60− fixUpstreamPkgs = self: super: {
90+ ZSH_COMP_DIR="$out/share/zsh/vendor-completions"
61− algebraic-graphs = pkgs.haskell.lib.doJailbreak
91+ mkdir -p "$ZSH_COMP_DIR"
62− (self.callCabal2nix "algebraic-graphs" (pkgs.fetchFromGitHub {
92+ "$out/bin/${exeName}" --zsh-completion-script "$out/bin/${exeName}" >"$ZSH_COMP_DIR/_ob"
63− owner = "snowleopard";
64− repo = "alga";
65− rev = "480a73137e9b38ad3f1bc2c628847953d2fb3e25";
66− sha256 = "0dpwi5ffs88brl3lz51bwb004c6zm8ds8pkw1vzsg2a6aaiyhlzl";
67− }) {});
68
93
69− # Need deriveSomeUniverse
94+ FISH_COMP_DIR="$out/share/fish/vendor_completions.d"
70− # PR: https://github.com/dmwit/universe/pull/32
95+ mkdir -p "$FISH_COMP_DIR"
71− universe-template = self.callCabal2nix "universe-template" (pkgs.fetchFromGitHub {
96+ "$out/bin/${exeName}" --fish-completion-script "$out/bin/${exeName}" >"$FISH_COMP_DIR/ob.fish"
72− owner = "obsidiansystems";
97+ '';
73− repo = "universe";
98+ });
74− rev = "5a2fc823caa4163411d7e41aa80e67cefb15944a";
99+ in {
75− sha256 = "0ll2z0fh18z6x8jl8kbp7ldagwccz3wjmvrw1gw752z058n82yfa";
100+ obelisk-command = addOptparseApplicativeCompletionScripts "ob" (haskellLib.justStaticExecutables super.obelisk-command);
76− } + /template) {};
101+ obelisk-selftest = haskellLib.justStaticExecutables super.obelisk-selftest;
77− };
102+ })
78
103
79− cleanSource = builtins.filterSource (name: _: let baseName = builtins.baseNameOf name; in !(
104+ ];
80− builtins.match "^\\.ghc\\.environment.*" baseName != null ||
81− baseName == "cabal.project.local"
82− ));
105+ };
83
106
84− executableConfig = import ./lib/executable-config { nixpkgs = pkgs; filterGitSource = cleanSource; };
107+ reflex-platform = getReflexPlatform' false system;
108+ inherit (reflex-platform) hackGet nixpkgs;
109+ pkgs = nixpkgs;
85
110
86− addLibs = self: super: {
111+ # The haskell environment used to build Obelisk itself, e.g. the 'ob' command
87− obelisk-asset-manifest = self.callCabal2nix "obelisk-asset-manifest" (hackGet ./lib/asset + "/manifest") {};
112+ ghcObelisk = reflex-platform.ghc;
88− obelisk-asset-serve-snap = self.callCabal2nix "obelisk-asset-serve-snap" (hackGet ./lib/asset + "/serve-snap") {};
89− obelisk-backend = self.callCabal2nix "obelisk-backend" (cleanSource ./lib/backend) {};
90− obelisk-cliapp = self.callCabal2nix "obelisk-cliapp" (cleanSource ./lib/cliapp) {};
91− obelisk-command = (self.callCabal2nix "obelisk-command" (cleanSource ./lib/command) {}).overrideAttrs
92− (drv: {
93− buildInputs = drv.buildInputs ++ [ pkgs.makeWrapper ];
94− postInstall = ''
95− ${drv.postInstall or ""}
96− # Install migrations
97− cp -r ${./migration} $out/migration;
98− '';
99− postFixup = ''
100− ${drv.postFixup or ""}
101− # Make `ob` reference its runtime dependencies.
102− wrapProgram "$out"/bin/ob --prefix PATH : ${pkgs.lib.makeBinPath (commandRuntimeDeps pkgs)}
103− '';
104− });
105− obelisk-executable-config = executableConfig.haskellPackage self;
106− obelisk-executable-config-inject = executableConfig.platforms.web.inject self;
107− obelisk-frontend = self.callCabal2nix "obelisk-frontend" (cleanSource ./lib/frontend) {};
108− obelisk-migration = self.callCabal2nix "obelisk-migration" (cleanSource ./lib/migration) {};
109− obelisk-run = self.callCabal2nix "obelisk-run" (cleanSource ./lib/run) {};
110− obelisk-route = self.callCabal2nix "obelisk-route" (cleanSource ./lib/route) {};
111− obelisk-selftest = self.callCabal2nix "obelisk-selftest" (cleanSource ./lib/selftest) {};
112− obelisk-snap = self.callCabal2nix "obelisk-snap" (cleanSource ./lib/snap) {};
113− obelisk-snap-extras = self.callCabal2nix "obelisk-snap-extras" (cleanSource ./lib/snap-extras) {};
114− };
115
113
116 inherit (import ./lib/asset/assets.nix { inherit nixpkgs; }) mkAssets;
114 inherit (import ./lib/asset/assets.nix { inherit nixpkgs; }) mkAssets;
117
115
118− defaultHaskellOverrides = composeExtensions fixUpstreamPkgs addLibs;
119−in
120−with pkgs.lib;
116+ haskellLib = pkgs.haskell.lib;
117+
121−rec {
118+in rec {
122 inherit reflex-platform;
119 inherit reflex-platform;
123 inherit (reflex-platform) nixpkgs pinBuildInputs;
120 inherit (reflex-platform) nixpkgs pinBuildInputs;
121+ inherit (nixpkgs) lib;
124 pathGit = ./.; # Used in CI by the migration graph hash algorithm to correctly ignore files.
122 pathGit = ./.; # Used in CI by the migration graph hash algorithm to correctly ignore files.
125 path = reflex-platform.filterGit ./.;
123 path = reflex-platform.filterGit ./.;
126 obelisk = ghcObelisk;
124 obelisk = ghcObelisk;
@@ -133,7 +131,7 @@ rec {
133
131
134 PATH="${command}/bin:$PATH"
132 PATH="${command}/bin:$PATH"
135 export OBELISK_IMPL="${hackGet ./.}"
133 export OBELISK_IMPL="${hackGet ./.}"
136− "${justStaticExecutables' ghcObelisk.obelisk-selftest}/bin/obelisk-selftest" "$@"
134+ "${ghcObelisk.obelisk-selftest}/bin/obelisk-selftest" "$@"
137 '';
135 '';
138 #TODO: Why can't I build ./skeleton directly as a derivation? `nix-build -E ./.` doesn't work
136 #TODO: Why can't I build ./skeleton directly as a derivation? `nix-build -E ./.` doesn't work
139 skeleton = pkgs.runCommand "skeleton" {
137 skeleton = pkgs.runCommand "skeleton" {
@@ -141,8 +139,7 @@ rec {
141 } ''
139 } ''
142 ln -s "$dir" "$out"
140 ln -s "$dir" "$out"
143 '';
141 '';
144− nullIfAbsent = p: if pathExists p then p else null;
142+ nullIfAbsent = p: if lib.pathExists p then p else null;
145− haskellOverrides = addLibs;
146 #TODO: Avoid copying files within the nix store. Right now, obelisk-asset-manifest-generate copies files into a big blob so that the android/ios static assets can be imported from there; instead, we should get everything lined up right before turning it into an APK, so that copies, if necessary, only exist temporarily.
143 #TODO: Avoid copying files within the nix store. Right now, obelisk-asset-manifest-generate copies files into a big blob so that the android/ios static assets can be imported from there; instead, we should get everything lined up right before turning it into an APK, so that copies, if necessary, only exist temporarily.
147 processAssets = { src, packageName ? "obelisk-generated-static", moduleName ? "Obelisk.Generated.Static" }: pkgs.runCommand "asset-manifest" {
144 processAssets = { src, packageName ? "obelisk-generated-static", moduleName ? "Obelisk.Generated.Static" }: pkgs.runCommand "asset-manifest" {
148 inherit src;
145 inherit src;
@@ -159,7 +156,7 @@ rec {
159 compressedJs = frontend: pkgs.runCommand "compressedJs" { buildInputs = [ pkgs.closurecompiler ]; } ''
156 compressedJs = frontend: pkgs.runCommand "compressedJs" { buildInputs = [ pkgs.closurecompiler ]; } ''
160 mkdir $out
157 mkdir $out
161 cd $out
158 cd $out
162− ln -s "${justStaticExecutables frontend}/bin/frontend.jsexe/all.js" all.unminified.js
159+ ln -s "${haskellLib.justStaticExecutables frontend}/bin/frontend.jsexe/all.js" all.unminified.js
163 closure-compiler --externs "${reflex-platform.ghcjsExternsJs}" -O ADVANCED --jscomp_warning=checkVars --create_source_map="all.js.map" --source_map_format=V3 --js_output_file="all.js" all.unminified.js
160 closure-compiler --externs "${reflex-platform.ghcjsExternsJs}" -O ADVANCED --jscomp_warning=checkVars --create_source_map="all.js.map" --source_map_format=V3 --js_output_file="all.js" all.unminified.js
164 echo "//# sourceMappingURL=all.js.map" >> all.js
161 echo "//# sourceMappingURL=all.js.map" >> all.js
165 '';
162 '';
@@ -235,7 +232,7 @@ rec {
235 pkgs.runCommand "serverExe" {} ''
232 pkgs.runCommand "serverExe" {} ''
236 mkdir $out
233 mkdir $out
237 set -eux
234 set -eux
238− ln -s "${justStaticExecutables backend}"/bin/* $out/
235+ ln -s "${haskellLib.justStaticExecutables backend}"/bin/* $out/
239 ln -s "${mkAssets assets}" $out/static.assets
236 ln -s "${mkAssets assets}" $out/static.assets
240 cp -r ${config} $out/config
237 cp -r ${config} $out/config
241 ln -s ${mkAssets (compressedJs frontend)} $out/frontend.jsexe.assets
238 ln -s ${mkAssets (compressedJs frontend)} $out/frontend.jsexe.assets
@@ -274,18 +271,17 @@ rec {
274 staticName = "obelisk-generated-static";
271 staticName = "obelisk-generated-static";
275 processedStatic = processAssets { src = staticFiles; };
272 processedStatic = processAssets { src = staticFiles; };
276 # The packages whose names and roles are defined by this package
273 # The packages whose names and roles are defined by this package
277− predefinedPackages = filterAttrs (_: x: x != null) {
274+ predefinedPackages = lib.filterAttrs (_: x: x != null) {
278 ${frontendName} = nullIfAbsent (base + "/frontend");
275 ${frontendName} = nullIfAbsent (base + "/frontend");
279 ${commonName} = nullIfAbsent (base + "/common");
276 ${commonName} = nullIfAbsent (base + "/common");
280 ${backendName} = nullIfAbsent (base + "/backend");
277 ${backendName} = nullIfAbsent (base + "/backend");
281 };
278 };
282 combinedPackages = predefinedPackages // packages;
279 combinedPackages = predefinedPackages // packages;
283 projectOverrides = self: super: {
280 projectOverrides = self: super: {
284− ${staticName} = dontHaddock (self.callCabal2nix staticName processedStatic.haskellManifest {});
281+ ${staticName} = haskellLib.dontHaddock (self.callCabal2nix staticName processedStatic.haskellManifest {});
285− ${backendName} = addBuildDepend super.${backendName} self.obelisk-run;
282+ ${backendName} = haskellLib.addBuildDepend super.${backendName} self.obelisk-run;
286 };
283 };
287− totalOverrides = composeExtensions (composeExtensions defaultHaskellOverrides projectOverrides) overrides;
284+ totalOverrides = lib.composeExtensions projectOverrides overrides;
288− inherit (nixpkgs) lib;
289 inherit (lib.strings) hasPrefix;
285 inherit (lib.strings) hasPrefix;
290 privateConfigDirs = ["config/backend"];
286 privateConfigDirs = ["config/backend"];
291 injectableConfig = builtins.filterSource (path: _:
287 injectableConfig = builtins.filterSource (path: _:
@@ -296,16 +292,16 @@ rec {
296 overrides = totalOverrides;
292 overrides = totalOverrides;
297 packages = combinedPackages;
293 packages = combinedPackages;
298 shells = {
294 shells = {
299− ghcSavedSplices = (filter (x: hasAttr x combinedPackages) [
295+ ghcSavedSplices = (lib.filter (x: lib.hasAttr x combinedPackages) [
300 commonName
296 commonName
301 frontendName
297 frontendName
302 ]);
298 ]);
303− ghc = (filter (x: hasAttr x combinedPackages) [
299+ ghc = (lib.filter (x: lib.hasAttr x combinedPackages) [
304 backendName
300 backendName
305 commonName
301 commonName
306 frontendName
302 frontendName
307 ]);
303 ]);
308− ghcjs = filter (x: hasAttr x combinedPackages) [
304+ ghcjs = lib.filter (x: lib.hasAttr x combinedPackages) [
309 frontendName
305 frontendName
310 commonName
306 commonName
311 ];
307 ];
@@ -314,14 +310,14 @@ rec {
314 ${if android == null then null else frontendName} = {
310 ${if android == null then null else frontendName} = {
315 executableName = "frontend";
311 executableName = "frontend";
316 ${if builtins.pathExists staticFiles then "assets" else null} =
312 ${if builtins.pathExists staticFiles then "assets" else null} =
317− executableConfig.platforms.android.inject injectableConfig processedStatic.symlinked;
313+ nixpkgs.obeliskExecutableConfig.platforms.android.inject injectableConfig processedStatic.symlinked;
318 } // android;
314 } // android;
319 };
315 };
320 ios = {
316 ios = {
321 ${if ios == null then null else frontendName} = {
317 ${if ios == null then null else frontendName} = {
322 executableName = "frontend";
318 executableName = "frontend";
323 ${if builtins.pathExists staticFiles then "staticSrc" else null} =
319 ${if builtins.pathExists staticFiles then "staticSrc" else null} =
324− executableConfig.platforms.ios.inject injectableConfig processedStatic.symlinked;
320+ nixpkgs.obeliskExecutableConfig.platforms.ios.inject injectableConfig processedStatic.symlinked;
325 } // ios;
321 } // ios;
326 };
322 };
327 passthru = { inherit android ios packages overrides tools shellToolOverrides withHoogle staticFiles; };
323 passthru = { inherit android ios packages overrides tools shellToolOverrides withHoogle staticFiles; };
@@ -334,13 +330,11 @@ rec {
334 linuxExe = linuxExe (base + "/config");
330 linuxExe = linuxExe (base + "/config");
335 exe = serverOn system (base + "/config") ;
331 exe = serverOn system (base + "/config") ;
336 server = args@{ hostName, adminEmail, routeHost, enableHttps, config }: let
332 server = args@{ hostName, adminEmail, routeHost, enableHttps, config }: let
337− injectableConfig = builtins.filterSource (path: _: !(hasPrefix (toString config + "/backend") (toString path))) config;
333+ injectableConfig = builtins.filterSource (path: _: !(lib.hasPrefix (toString config + "/backend") (toString path))) config;
338 in server (args // { exe = linuxExe injectableConfig; });
334 in server (args // { exe = linuxExe injectableConfig; });
339 obelisk = import (base + "/.obelisk/impl") {};
335 obelisk = import (base + "/.obelisk/impl") {};
340 };
336 };
341 haskellPackageSets = {
337 haskellPackageSets = {
342− ghc = reflex-platform.ghc.override {
338+ inherit (reflex-platform) ghc;
343− overrides = defaultHaskellOverrides;
344− };
345 };
339 };
346}
340}
dep/reflex-platform/github.json+2−2
@@ -2,6 +2,6 @@
2 "owner": "reflex-frp",
2 "owner": "reflex-frp",
3 "repo": "reflex-platform",
3 "repo": "reflex-platform",
4 "branch": "develop",
4 "branch": "develop",
5− "rev": "92f235e0533b9722be729d785a033faf21e81872",
5+ "rev": "0c022883469da05987810557b61d37b7ae3e922e",
6− "sha256": "1r3kcvy0zf6qdvnasins43hb77lpn0r26vvmnh3cf3yrvpy86sam"
6+ "sha256": "0aissxk9fpzymvr4qqnwkfvr5jya2h7qrxbx5byg0dv627six8yw"
7}
7}
lib/cliapp/obelisk-cliapp.cabal+1
@@ -12,6 +12,7 @@ library
12 , bytestring
12 , bytestring
13 , exceptions
13 , exceptions
14 , io-streams
14 , io-streams
15+ , lens
15 , logging-effect
16 , logging-effect
16 , monad-loops
17 , monad-loops
17 , mtl
18 , mtl
lib/cliapp/src/Obelisk/CliApp.hs+6−2
@@ -8,7 +8,6 @@ module Obelisk.CliApp
8 -- .Types
8 -- .Types
9 CliLog
9 CliLog
10 , CliThrow
10 , CliThrow
11− , Cli
12 , CliT(..)
11 , CliT(..)
13 , runCli
12 , runCli
14 , CliConfig
13 , CliConfig
@@ -22,22 +21,27 @@ module Obelisk.CliApp
22 , withSpinner'
21 , withSpinner'
23
22
24 -- .Logging
23 -- .Logging
24+ , AsUnstructuredError (..)
25 , newCliConfig
25 , newCliConfig
26 , getLogLevel
26 , getLogLevel
27 , putLog
27 , putLog
28 , failWith
28 , failWith
29+ , errorToWarning
29 , withExitFailMessage
30 , withExitFailMessage
30
31
31 -- Control.Monad.Log
32 -- Control.Monad.Log
32 , Severity (..)
33 , Severity (..)
33
34
34 -- .Process
35 -- .Process
35− , ProcessFailed (..)
36+ , ProcessFailure (..)
37+ , AsProcessFailure (..)
36 , readProcessAndLogStderr
38 , readProcessAndLogStderr
39+ , readProcessAndLogOutput
37 , callProcessAndLogOutput
40 , callProcessAndLogOutput
38 , createProcess_
41 , createProcess_
39 , callProcess
42 , callProcess
40 , callCommand
43 , callCommand
44+ , reconstructCommand
41 ) where
45 ) where
42
46
43import Control.Monad.Log (Severity (..))
47import Control.Monad.Log (Severity (..))
lib/cliapp/src/Obelisk/CliApp/Demo.hs+5−2
@@ -13,7 +13,10 @@ import Control.Monad.Catch (MonadMask)
13
13
14import Obelisk.CliApp
14import Obelisk.CliApp
15
15
16+cliDemo
16−cliDemo :: (MonadIO m, MonadMask m, Cli m, HasCliConfig m) => m ()
17+ :: ( MonadIO m, MonadMask m
18+ , CliLog m, HasCliConfig e m, CliThrow e m, AsProcessFailure e, AsUnstructuredError e)
19+ => m ()
17cliDemo = withSpinner "CLI Demo" $ do
20cliDemo = withSpinner "CLI Demo" $ do
18 putLog Notice "This demo will showcase the CLI library functionality"
21 putLog Notice "This demo will showcase the CLI library functionality"
19 _ <- withSpinner' "Searching long for something" (Just $ \c -> "Discovered " <> T.pack (show c) <> " objects") $ do
22 _ <- withSpinner' "Searching long for something" (Just $ \c -> "Discovered " <> T.pack (show c) <> " objects") $ do
@@ -40,7 +43,7 @@ cliDemo = withSpinner "CLI Demo" $ do
40 withSpinner "Looking around" $ do
43 withSpinner "Looking around" $ do
41 delay
44 delay
42 output <- readProcessAndLogStderr Notice $ proc "ls" ["-l", "/"]
45 output <- readProcessAndLogStderr Notice $ proc "ls" ["-l", "/"]
43− putLog Notice $ "Output was: " <> T.pack output
46+ putLog Notice $ "Output was: " <> output
44 delay
47 delay
45 callProcessAndLogOutput (Notice, Error) $ proc "ls" ["-l", "/does-not-exist"]
48 callProcessAndLogOutput (Notice, Error) $ proc "ls" ["-l", "/does-not-exist"]
46 delay
49 delay
lib/cliapp/src/Obelisk/CliApp/Logging.hs+43−16
@@ -4,11 +4,13 @@
4{-# LANGUAGE LambdaCase #-}
4{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE OverloadedStrings #-}
6{-# LANGUAGE OverloadedStrings #-}
7+{-# LANGUAGE RankNTypes #-}
7{-# LANGUAGE ScopedTypeVariables #-}
8{-# LANGUAGE ScopedTypeVariables #-}
8-- | Provides a logging handler that facilitates safe ouputting to terminal using MVar based locking.
9-- | Provides a logging handler that facilitates safe ouputting to terminal using MVar based locking.
9-- | Spinner.hs and Process.hs work on this guarantee.
10-- | Spinner.hs and Process.hs work on this guarantee.
10module Obelisk.CliApp.Logging
11module Obelisk.CliApp.Logging
12+ ( AsUnstructuredError (..)
11− ( newCliConfig
13+ , newCliConfig
12 , runCli
14 , runCli
13 , verboseLogLevel
15 , verboseLogLevel
14 , isOverwrite
16 , isOverwrite
@@ -18,6 +20,7 @@ module Obelisk.CliApp.Logging
18 , putLog
20 , putLog
19 , putLogRaw
21 , putLogRaw
20 , failWith
22 , failWith
23+ , errorToWarning
21 , withExitFailMessage
24 , withExitFailMessage
22 , writeLog
25 , writeLog
23 , allowUserToMakeLoggingVerbose
26 , allowUserToMakeLoggingVerbose
@@ -27,9 +30,10 @@ module Obelisk.CliApp.Logging
27
30
28import Control.Concurrent (ThreadId, forkIO, killThread, threadDelay)
31import Control.Concurrent (ThreadId, forkIO, killThread, threadDelay)
29import Control.Concurrent.MVar (modifyMVar_, newMVar)
32import Control.Concurrent.MVar (modifyMVar_, newMVar)
33+import Control.Lens (Prism', review)
30import Control.Monad (unless, void, when)
34import Control.Monad (unless, void, when)
31import Control.Monad.Catch (MonadCatch, MonadMask, bracket, catch, throwM)
35import Control.Monad.Catch (MonadCatch, MonadMask, bracket, catch, throwM)
32−import Control.Monad.Except (MonadError, throwError)
36+import Control.Monad.Except (throwError)
33import Control.Monad.IO.Class (liftIO)
37import Control.Monad.IO.Class (liftIO)
34import Control.Monad.Log (Severity (..), WithSeverity (..), logMessage, runLoggingT)
38import Control.Monad.Log (Severity (..), WithSeverity (..), logMessage, runLoggingT)
35import Control.Monad.Loops (iterateUntil)
39import Control.Monad.Loops (iterateUntil)
@@ -48,17 +52,23 @@ import System.IO (BufferMode (NoBuffering), hFlush, hReady, hSetBuffering, stder
48import qualified Obelisk.CliApp.TerminalString as TS
52import qualified Obelisk.CliApp.TerminalString as TS
49import Obelisk.CliApp.Types
53import Obelisk.CliApp.Types
50
54
51−newCliConfig :: Severity -> Bool -> Bool -> IO CliConfig
55+newCliConfig
56+ :: Severity
57+ -> Bool
58+ -> Bool
59+ -> (e -> (Text, Int))
60+ -> IO (CliConfig e)
52−newCliConfig sev noColor noSpinner = do
61+newCliConfig sev noColor noSpinner errorLogExitCode = do
53 level <- newIORef sev
62 level <- newIORef sev
54 lock <- newMVar False
63 lock <- newMVar False
55 tipDisplayed <- newIORef False
64 tipDisplayed <- newIORef False
56 stack <- newIORef ([], [])
65 stack <- newIORef ([], [])
57− return $ CliConfig level noColor noSpinner lock tipDisplayed stack
66+ return $ CliConfig level noColor noSpinner lock tipDisplayed stack errorLogExitCode
58
67
59−runCli :: MonadIO m => CliConfig -> CliT m a -> m a
68+runCli :: MonadIO m => CliConfig e -> CliT e m a -> m a
60runCli c =
69runCli c =
61 flip runLoggingT (handleLog c)
70 flip runLoggingT (handleLog c)
71+ . flip runReaderT (_cliConfig_errorLogExitCode c)
62 . unDieT
72 . unDieT
63 . flip runReaderT c
73 . flip runReaderT c
64 . unCliT
74 . unCliT
@@ -77,18 +87,18 @@ getSeverity = \case
77 Output_LogRaw (WithSeverity sev _) -> Just sev
87 Output_LogRaw (WithSeverity sev _) -> Just sev
78 _ -> Nothing
88 _ -> Nothing
79
89
80−getLogLevel :: (MonadIO m, HasCliConfig m) => m Severity
90+getLogLevel :: (MonadIO m, HasCliConfig e m) => m Severity
81getLogLevel = getLogLevel' =<< getCliConfig
91getLogLevel = getLogLevel' =<< getCliConfig
82
92
83−getLogLevel' :: MonadIO m => CliConfig -> m Severity
93+getLogLevel' :: MonadIO m => CliConfig e -> m Severity
84getLogLevel' = liftIO . readIORef . _cliConfig_logLevel
94getLogLevel' = liftIO . readIORef . _cliConfig_logLevel
85
95
86−setLogLevel :: (MonadIO m, HasCliConfig m) => Severity -> m ()
96+setLogLevel :: (MonadIO m, HasCliConfig e m) => Severity -> m ()
87setLogLevel sev = do
97setLogLevel sev = do
88 l <- _cliConfig_logLevel <$> getCliConfig
98 l <- _cliConfig_logLevel <$> getCliConfig
89 liftIO $ writeIORef l sev
99 liftIO $ writeIORef l sev
90
100
91−handleLog :: MonadIO m => CliConfig -> Output -> m ()
101+handleLog :: MonadIO m => CliConfig e -> Output -> m ()
92handleLog conf output = do
102handleLog conf output = do
93 level <- getLogLevel' conf
103 level <- getLogLevel' conf
94 liftIO $ modifyMVar_ (_cliConfig_lock conf) $ \wasOverwriting -> do
104 liftIO $ modifyMVar_ (_cliConfig_lock conf) $ \wasOverwriting -> do
@@ -126,17 +136,34 @@ handleLog' noColor output = do
126 return $ isOverwrite output
136 return $ isOverwrite output
127
137
128-- | Like `putLog` but without the implicit newline added.
138-- | Like `putLog` but without the implicit newline added.
129−putLogRaw :: Cli m => Severity -> Text -> m ()
139+putLogRaw :: CliLog m => Severity -> Text -> m ()
130putLogRaw sev = logMessage . Output_LogRaw . WithSeverity sev
140putLogRaw sev = logMessage . Output_LogRaw . WithSeverity sev
131
141
142+-- | Indicates unstructured errors form one variant (or conceptual projection)
143+-- of the error type.
144+--
145+-- Shouldn't really use this, but who has time to clean up that much!
146+class AsUnstructuredError e where
147+ asUnstructuredError :: Prism' e Text
148+
149+instance AsUnstructuredError Text where
150+ asUnstructuredError = id
151+
132-- | Like `putLog Alert` but also abrupts the program.
152-- | Like `putLog Alert` but also abrupts the program.
133−failWith :: MonadError Text m => Text -> m a
153+failWith :: (CliThrow e m, AsUnstructuredError e) => Text -> m a
134−failWith = throwError
154+failWith = throwError . review asUnstructuredError
155+
156+errorToWarning
157+ :: (HasCliConfig e m, CliThrow e m, CliLog m)
158+ => e -> m ()
159+errorToWarning e = do
160+ c <- getCliConfig
161+ putLog Warning $ fst $ _cliConfig_errorLogExitCode c e
135
162
136-- | Intercept ExitFailure exceptions and log the given alert before exiting.
163-- | Intercept ExitFailure exceptions and log the given alert before exiting.
137--
164--
138-- This is useful when you want to provide contextual information to a deeper failure.
165-- This is useful when you want to provide contextual information to a deeper failure.
139−withExitFailMessage :: (Cli m, MonadCatch m) => Text -> m a -> m a
166+withExitFailMessage :: (CliLog m, MonadCatch m) => Text -> m a -> m a
140withExitFailMessage msg f = f `catch` \(e :: ExitCode) -> do
167withExitFailMessage msg f = f `catch` \(e :: ExitCode) -> do
141 case e of
168 case e of
142 ExitFailure _ -> putLog Alert msg
169 ExitFailure _ -> putLog Alert msg
@@ -162,7 +189,7 @@ writeLog withNewLine noColor (WithSeverity severity s)
162--
189--
163-- Call this function in a thread, and kill it to turn off keystroke monitoring.
190-- Call this function in a thread, and kill it to turn off keystroke monitoring.
164allowUserToMakeLoggingVerbose
191allowUserToMakeLoggingVerbose
165− :: (MonadIO m, MonadMask m, Cli m, HasCliConfig m)
192+ :: (MonadIO m, MonadMask m, CliLog m, HasCliConfig e m)
166 => String -- ^ The key to press in order to make logging verbose
193 => String -- ^ The key to press in order to make logging verbose
167 -> m ()
194 -> m ()
168allowUserToMakeLoggingVerbose keyCode = bracket showTip (liftIO . killThread) $ \_ -> do
195allowUserToMakeLoggingVerbose keyCode = bracket showTip (liftIO . killThread) $ \_ -> do
@@ -195,7 +222,7 @@ getChars = reverse <$> f mempty
195 True -> f (x:xs)
222 True -> f (x:xs)
196 False -> return (x:xs)
223 False -> return (x:xs)
197
224
198−fork :: (HasCliConfig m, MonadIO m) => CliT IO () -> m ThreadId
225+fork :: (HasCliConfig e m, MonadIO m) => CliT e IO () -> m ThreadId
199fork f = do
226fork f = do
200 c <- getCliConfig
227 c <- getCliConfig
201 liftIO $ forkIO $ runCli c f
228 liftIO $ forkIO $ runCli c f
lib/cliapp/src/Obelisk/CliApp/Process.hs+73−38
@@ -9,25 +9,29 @@
9-- | An extension of `System.Process` that integrates with logging (`Obelisk.CLI.Logging`)
9-- | An extension of `System.Process` that integrates with logging (`Obelisk.CLI.Logging`)
10-- and is thus spinner friendly.
10-- and is thus spinner friendly.
11module Obelisk.CliApp.Process
11module Obelisk.CliApp.Process
12− ( ProcessFailed (..)
12+ ( ProcessFailure (..)
13+ , AsProcessFailure (..)
13 , readProcessAndLogStderr
14 , readProcessAndLogStderr
15+ , readProcessAndLogOutput
14 , callProcessAndLogOutput
16 , callProcessAndLogOutput
15 , createProcess
17 , createProcess
16 , createProcess_
18 , createProcess_
17 , callProcess
19 , callProcess
18 , callCommand
20 , callCommand
21+ , reconstructCommand
19 ) where
22 ) where
20
23
21−import Control.Applicative (liftA2)
24+import Control.Monad ((<=<), join, void)
22−import Control.Monad (void, (<=<))
23−import Control.Monad.Catch (Exception(..), MonadMask, throwM)
25+import Control.Monad.Except (throwError)
24import Control.Monad.IO.Class (MonadIO, liftIO)
26import Control.Monad.IO.Class (MonadIO, liftIO)
27+import Control.Lens (Prism', review)
28+import qualified Data.ByteString as BS
25import qualified Data.ByteString.Char8 as BSC
29import qualified Data.ByteString.Char8 as BSC
26import Data.Function (fix)
30import Data.Function (fix)
27import Data.Monoid ((<>))
31import Data.Monoid ((<>))
32+import Data.Text (Text)
28import qualified Data.Text as T
33import qualified Data.Text as T
29−import Data.Text.Encoding (decodeUtf8)
34+import qualified Data.Text.Encoding as T
30−import qualified Data.Text.IO as T
31import System.Exit (ExitCode (..))
35import System.Exit (ExitCode (..))
32import System.IO (Handle)
36import System.IO (Handle)
33import System.IO.Streams (InputStream, handleToInputStream)
37import System.IO.Streams (InputStream, handleToInputStream)
@@ -39,60 +43,90 @@ import qualified System.Process as Process
39
43
40import Control.Monad.Log (Severity (..))
44import Control.Monad.Log (Severity (..))
41import Obelisk.CliApp.Logging (putLog, putLogRaw)
45import Obelisk.CliApp.Logging (putLog, putLogRaw)
42−import Obelisk.CliApp.Types (Cli)
46+import Obelisk.CliApp.Types (CliLog, CliThrow)
43
47
48+-- TODO put back in `Obelisk.CliApp.Process` and use prisms for extensible exceptions
44−data ProcessFailed = ProcessFailed Process.CmdSpec Int -- exit code
49+data ProcessFailure = ProcessFailure Process.CmdSpec Int -- exit code
45 deriving Show
50 deriving Show
46
51
47−instance Exception ProcessFailed where
52+-- | Indicates arbitrary process failures form one variant (or conceptual projection) of
48− displayException (ProcessFailed spec exitCode) =
53+-- the error type.
49− unwords ["ProcessFailed", reconstructCommand spec, show exitCode]
54+class AsProcessFailure e where
55+ asProcessFailure :: Prism' e ProcessFailure
56+
57+instance AsProcessFailure ProcessFailure where
58+ asProcessFailure = id
50
59
51readProcessAndLogStderr
60readProcessAndLogStderr
52− :: (MonadIO m, MonadMask m, Cli m)
61+ :: (MonadIO m, CliLog m, CliThrow e m, AsProcessFailure e)
53− => Severity -> CreateProcess -> m String
62+ => Severity -> CreateProcess -> m Text
54readProcessAndLogStderr sev process = do
63readProcessAndLogStderr sev process = do
55 (out, _err) <- withProcess process $ \_out err -> do
64 (out, _err) <- withProcess process $ \_out err -> do
56 streamToLog =<< liftIO (streamHandle sev err)
65 streamToLog =<< liftIO (streamHandle sev err)
57− -- TODO: Why are we using Text here?
58− liftIO $ T.unpack . T.strip <$> T.hGetContents out
66+ liftIO $ T.decodeUtf8 <$> BS.hGetContents out
59
67
60−-- | Like `System.Process.callProcess` but logs the combined output--stdout and stderr with the corresponding
68+-- | Like `System.Process.readProcess` but logs the combined output (stdout and stderr)
61−-- severity.
69+-- with the corresponding severity.
62--
70--
63−-- Usually this function is called as `callProcessAndLogOutput (Debug, Error)`. However some processes
71+-- Usually this function is called as `callProcessAndLogOutput (Debug, Error)`. However
72+-- some processes are known to spit out diagnostic or informative messages in stderr, in
73+-- which case it is advisable to call it with a non-Error severity for stderr, like
74+-- `callProcessAndLogOutput (Debug, Debug)`.
75+readProcessAndLogOutput
76+ :: (MonadIO m, CliLog m, CliThrow e m, AsProcessFailure e)
77+ => (Severity, Severity) -> CreateProcess -> m Text
78+readProcessAndLogOutput (sev_out, sev_err) process = do
79+ (_, Just out, Just err, p) <- createProcess $ process
80+ { std_out = CreatePipe , std_err = CreatePipe }
81+
82+ -- TODO interleave stdout and stderr in log correctly
83+ streamToLog =<< liftIO (streamHandle sev_err err)
84+ outText <- liftIO $ T.decodeUtf8 <$> BS.hGetContents out
85+ putLogRaw sev_out outText
86+
87+ liftIO (waitForProcess p) >>= \case
88+ ExitSuccess -> pure outText
89+ ExitFailure code -> throwError $ review asProcessFailure $ ProcessFailure (cmdspec process) code
90+
91+-- | Like `System.Process.callProcess` but logs the combined output (stdout and stderr)
92+-- with the corresponding severity.
93+--
94+-- Usually this function is called as `callProcessAndLogOutput (Debug, Error)`. However
64−-- are known to spit out diagnostic or informative messages in stderr, in which case it is advisable to call
95+-- some processes are known to spit out diagnostic or informative messages in stderr, in
96+-- which case it is advisable to call it with a non-Error severity for stderr, like
65−-- it with a non-Error severity for stderr, like `callProcessAndLogOutput (Debug, Debug)`.
97+-- `callProcessAndLogOutput (Debug, Debug)`.
66callProcessAndLogOutput
98callProcessAndLogOutput
67− :: (MonadIO m, MonadMask m, Cli m)
99+
100+ :: (MonadIO m, CliLog m, CliThrow e m, AsProcessFailure e)
68 => (Severity, Severity) -> CreateProcess -> m ()
101 => (Severity, Severity) -> CreateProcess -> m ()
69−callProcessAndLogOutput (sev_out, sev_err) process = do
102+callProcessAndLogOutput (sev_out, sev_err) process =
70 void $ withProcess process $ \out err -> do
103 void $ withProcess process $ \out err -> do
71− stream <- liftIO $ do
104+ stream <- liftIO $ join $ combineStream
72− uncurry combineStream =<< liftA2 (,) (streamHandle sev_out out) (streamHandle sev_err err)
105+ <$> streamHandle sev_out out
106+ <*> streamHandle sev_err err
73 streamToLog stream
107 streamToLog stream
74 where
108 where
75 combineStream s1 s2 = concurrentMerge [s1, s2]
109 combineStream s1 s2 = concurrentMerge [s1, s2]
76
110
77-- | Like `System.Process.createProcess` but also logs (debug) the process being run
111-- | Like `System.Process.createProcess` but also logs (debug) the process being run
78createProcess
112createProcess
79− :: (MonadIO m, Cli m)
113+ :: (MonadIO m, CliLog m)
80 => CreateProcess -> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
114 => CreateProcess -> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
81createProcess p = do
115createProcess p = do
82− putLog Debug $ "Creating process: " <> T.pack (reconstructCommand (cmdspec p))
116+ putLog Debug $ "Creating process: " <> reconstructCommand (cmdspec p)
83 liftIO $ Process.createProcess p
117 liftIO $ Process.createProcess p
84
118
85-- | Like `System.Process.createProcess_` but also logs (debug) the process being run
119-- | Like `System.Process.createProcess_` but also logs (debug) the process being run
86createProcess_
120createProcess_
87− :: (MonadIO m, Cli m)
121+ :: (MonadIO m, CliLog m)
88 => String -> CreateProcess -> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
122 => String -> CreateProcess -> m (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
89createProcess_ name p = do
123createProcess_ name p = do
90− putLog Debug $ "Creating process " <> T.pack name <> ": " <> T.pack (reconstructCommand (cmdspec p))
124+ putLog Debug $ "Creating process " <> T.pack name <> ": " <> reconstructCommand (cmdspec p)
91 liftIO $ Process.createProcess p
125 liftIO $ Process.createProcess p
92
126
93-- | Like `System.Process.callProcess` but also logs (debug) the process being run
127-- | Like `System.Process.callProcess` but also logs (debug) the process being run
94callProcess
128callProcess
95− :: (MonadIO m, Cli m)
129+ :: (MonadIO m, CliLog m)
96 => String -> [String] -> m ()
130 => String -> [String] -> m ()
97callProcess exe args = do
131callProcess exe args = do
98 putLog Debug $ "Calling process " <> T.pack exe <> " with args: " <> T.pack (show args)
132 putLog Debug $ "Calling process " <> T.pack exe <> " with args: " <> T.pack (show args)
@@ -100,14 +134,14 @@ callProcess exe args = do
100
134
101-- | Like `System.Process.callCommand` but also logs (debug) the command being run
135-- | Like `System.Process.callCommand` but also logs (debug) the command being run
102callCommand
136callCommand
103− :: (MonadIO m, Cli m)
137+ :: (MonadIO m, CliLog m)
104 => String -> m ()
138 => String -> m ()
105callCommand cmd = do
139callCommand cmd = do
106 putLog Debug $ "Calling command " <> T.pack cmd
140 putLog Debug $ "Calling command " <> T.pack cmd
107 liftIO $ Process.callCommand cmd
141 liftIO $ Process.callCommand cmd
108
142
109withProcess
143withProcess
110− :: (MonadIO m, MonadMask m, Cli m)
144+ :: (MonadIO m, CliLog m, CliThrow e m, AsProcessFailure e)
111 => CreateProcess -> (Handle -> Handle -> m ()) -> m (Handle, Handle)
145 => CreateProcess -> (Handle -> Handle -> m ()) -> m (Handle, Handle)
112withProcess process f = do -- TODO: Use bracket.
146withProcess process f = do -- TODO: Use bracket.
113 -- FIXME: Using `withCreateProcess` here leads to something operating illegally on closed handles.
147 -- FIXME: Using `withCreateProcess` here leads to something operating illegally on closed handles.
@@ -118,7 +152,7 @@ withProcess process f = do -- TODO: Use bracket.
118
152
119 liftIO (waitForProcess p) >>= \case
153 liftIO (waitForProcess p) >>= \case
120 ExitSuccess -> return (out, err)
154 ExitSuccess -> return (out, err)
121− ExitFailure code -> throwM $ ProcessFailed (cmdspec process) code
155+ ExitFailure code -> throwError $ review asProcessFailure $ ProcessFailure (cmdspec process) code
122
156
123-- Create an input stream from the file handle, associating each item with the given severity.
157-- Create an input stream from the file handle, associating each item with the given severity.
124streamHandle :: Severity -> Handle -> IO (InputStream (Severity, BSC.ByteString))
158streamHandle :: Severity -> Handle -> IO (InputStream (Severity, BSC.ByteString))
@@ -126,16 +160,17 @@ streamHandle sev = Streams.map (sev,) <=< handleToInputStream
126
160
127-- | Read from an input stream and log its contents
161-- | Read from an input stream and log its contents
128streamToLog
162streamToLog
129− :: (MonadIO m, MonadMask m, Cli m)
163+ :: (MonadIO m, CliLog m)
130 => InputStream (Severity, BSC.ByteString) -> m ()
164 => InputStream (Severity, BSC.ByteString) -> m ()
131streamToLog stream = fix $ \loop -> do
165streamToLog stream = fix $ \loop -> do
132 liftIO (Streams.read stream) >>= \case
166 liftIO (Streams.read stream) >>= \case
133 Nothing -> return ()
167 Nothing -> return ()
134− Just (sev, line) -> putLogRaw sev (decodeUtf8 line) >> loop
168+ Just (sev, line) -> putLogRaw sev (T.decodeUtf8 line) >> loop
135
169
170+-- | Pretty print a 'CmdSpec'
136−reconstructCommand :: Process.CmdSpec -> String
171+reconstructCommand :: Process.CmdSpec -> Text
137−reconstructCommand (Process.ShellCommand str) = str
172+reconstructCommand (Process.ShellCommand str) = T.pack str
138reconstructCommand (Process.RawCommand c as) = processToShellString c as
173reconstructCommand (Process.RawCommand c as) = processToShellString c as
139 where
174 where
140− processToShellString cmd args = unwords $ map quoteAndEscape (cmd : args)
175+ processToShellString cmd args = T.unwords $ map quoteAndEscape (cmd : args)
141− quoteAndEscape x = T.unpack $ "'" <> T.replace "'" "'\''" (T.pack x) <> "'"
176+ quoteAndEscape x = "'" <> T.replace "'" "'\''" (T.pack x) <> "'"
lib/cliapp/src/Obelisk/CliApp/Spinner.hs+4−4
@@ -24,11 +24,11 @@ import System.Console.ANSI (Color (Blue, Cyan, Green, Red))
24
24
25import Obelisk.CliApp.Logging (allowUserToMakeLoggingVerbose, fork, putLog)
25import Obelisk.CliApp.Logging (allowUserToMakeLoggingVerbose, fork, putLog)
26import Obelisk.CliApp.TerminalString (TerminalString (..), enquiryCode)
26import Obelisk.CliApp.TerminalString (TerminalString (..), enquiryCode)
27−import Obelisk.CliApp.Types (Cli, CliConfig (..), HasCliConfig, Output (..), getCliConfig)
27+import Obelisk.CliApp.Types (CliLog, CliConfig (..), HasCliConfig, Output (..), getCliConfig)
28
28
29-- | Run an action with a CLI spinner.
29-- | Run an action with a CLI spinner.
30withSpinner
30withSpinner
31− :: (MonadIO m, MonadMask m, Cli m, HasCliConfig m)
31+ :: (MonadIO m, MonadMask m, CliLog m, HasCliConfig e m)
32 => Text -> m a -> m a
32 => Text -> m a -> m a
33withSpinner s = withSpinner' s $ Just $ const s
33withSpinner s = withSpinner' s $ Just $ const s
34
34
@@ -39,13 +39,13 @@ withSpinner s = withSpinner' s $ Just $ const s
39-- The 'no trail' property automatically carries over to sub-spinners (in that
39-- The 'no trail' property automatically carries over to sub-spinners (in that
40-- they won't leave a trail either).
40-- they won't leave a trail either).
41withSpinnerNoTrail
41withSpinnerNoTrail
42− :: (MonadIO m, MonadMask m, Cli m, HasCliConfig m)
42+ :: (MonadIO m, MonadMask m, CliLog m, HasCliConfig e m)
43 => Text -> m a -> m a
43 => Text -> m a -> m a
44withSpinnerNoTrail s = withSpinner' s Nothing
44withSpinnerNoTrail s = withSpinner' s Nothing
45
45
46-- | Advanced version that controls the display and content of the trail message.
46-- | Advanced version that controls the display and content of the trail message.
47withSpinner'
47withSpinner'
48− :: (MonadIO m, MonadMask m, Cli m, HasCliConfig m)
48+ :: (MonadIO m, MonadMask m, CliLog m, HasCliConfig e m)
49 => Text
49 => Text
50 -> Maybe (a -> Text) -- ^ Leave an optional trail with the given message creator
50 -> Maybe (a -> Text) -- ^ Leave an optional trail with the given message creator
51 -> m a
51 -> m a
lib/cliapp/src/Obelisk/CliApp/Types.hs+38−26
@@ -1,14 +1,18 @@
1{-# LANGUAGE ConstraintKinds #-}
1{-# LANGUAGE ConstraintKinds #-}
2{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FlexibleInstances #-}
4+{-# LANGUAGE FunctionalDependencies #-}
5+{-# LANGUAGE LambdaCase #-}
4{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE OverloadedStrings #-}
9+{-# LANGUAGE UndecidableInstances #-}
6module Obelisk.CliApp.Types where
10module Obelisk.CliApp.Types where
7
11
8import Control.Concurrent.MVar (MVar)
12import Control.Concurrent.MVar (MVar)
9import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow)
13import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow)
10import Control.Monad.Log (LoggingT, MonadLog, Severity (..), WithSeverity (..), logMessage)
14import Control.Monad.Log (LoggingT, MonadLog, Severity (..), WithSeverity (..), logMessage)
11−import Control.Monad.Reader (MonadIO, ReaderT (..), MonadReader, ask)
15+import Control.Monad.Reader (MonadIO, ReaderT (..), MonadReader (..), ask, mapReaderT)
12import Control.Monad.Writer (WriterT)
16import Control.Monad.Writer (WriterT)
13import Control.Monad.State (StateT)
17import Control.Monad.State (StateT)
14import Control.Monad.Except (ExceptT, MonadError (..))
18import Control.Monad.Except (ExceptT, MonadError (..))
@@ -32,40 +36,44 @@ data Output
32
36
33type CliLog m = MonadLog Output m
37type CliLog m = MonadLog Output m
34
38
35−type CliThrow m = MonadError Text m
39+type CliThrow e m = MonadError e m
36−
37−-- TODO could remove for granularity
38−type Cli m = (CliLog m, CliThrow m)
39
40
40-- | Log a message to the console.
41-- | Log a message to the console.
41--
42--
42-- Logs safely even if there are ongoing spinners.
43-- Logs safely even if there are ongoing spinners.
43−putLog :: Cli m => Severity -> Text -> m ()
44+putLog :: CliLog m => Severity -> Text -> m ()
44putLog sev = logMessage . Output_Log . WithSeverity sev
45putLog sev = logMessage . Output_Log . WithSeverity sev
45
46
46−newtype DieT m a = DieT { unDieT :: LoggingT Output m a }
47+newtype DieT e m a = DieT { unDieT :: ReaderT (e -> (Text, Int)) (LoggingT Output m) a }
47 deriving
48 deriving
48 ( Functor, Applicative, Monad, MonadIO
49 ( Functor, Applicative, Monad, MonadIO
49− , MonadReader r
50 , MonadThrow, MonadCatch, MonadMask
50 , MonadThrow, MonadCatch, MonadMask
51 , MonadLog Output
51 , MonadLog Output
52 )
52 )
53
53
54−instance MonadTrans DieT where
54+instance MonadTrans (DieT e) where
55− lift = DieT . lift
55+ lift = DieT . lift . lift
56+
57+-- | Error printer is private to DieT
58+instance MonadReader r m => MonadReader r (DieT e m) where
59+ ask = DieT $ lift $ ask
60+ local = (\f (DieT a) -> DieT $ f a) . mapReaderT . local
61+ reader = DieT . lift . lift . reader
56
62
57-- TODO generalize to bigger error types
63-- TODO generalize to bigger error types
58−instance MonadIO m => MonadError Text (DieT m) where
64+instance MonadIO m => MonadError e (DieT e m) where
59− throwError s = do
65+ throwError e = do
66+ handler <- DieT ask
67+ let (output, exitCode) = handler e
60− putLog Alert s
68+ putLog Alert output
61− liftIO $ exitWith $ ExitFailure 2
69+ liftIO $ exitWith $ ExitFailure exitCode
62
70
63 -- Cannot catch
71 -- Cannot catch
64 catchError m _ = m
72 catchError m _ = m
65
73
66--------------------------------------------------------------------------------
74--------------------------------------------------------------------------------
67
75
68−data CliConfig = CliConfig
76+data CliConfig e = CliConfig
69 { -- | We are capable of changing the log level at runtime
77 { -- | We are capable of changing the log level at runtime
70 _cliConfig_logLevel :: IORef Severity
78 _cliConfig_logLevel :: IORef Severity
71 , -- | Disallow coloured output
79 , -- | Disallow coloured output
@@ -78,36 +86,40 @@ data CliConfig = CliConfig
78 _cliConfig_tipDisplayed :: IORef Bool
86 _cliConfig_tipDisplayed :: IORef Bool
79 , -- | Stack of logs from nested spinners
87 , -- | Stack of logs from nested spinners
80 _cliConfig_spinnerStack :: IORef ([Bool], [TerminalString])
88 _cliConfig_spinnerStack :: IORef ([Bool], [TerminalString])
89+ , -- | Failure handler. How to log error and what exit status to use.
90+ _cliConfig_errorLogExitCode :: e -> (Text, Int)
81 }
91 }
82
92
83−class Monad m => HasCliConfig m where
93+class Monad m => HasCliConfig e m | m -> e where
84− getCliConfig :: m CliConfig
94+ getCliConfig :: m (CliConfig e)
85
95
86−instance HasCliConfig m => HasCliConfig (ReaderT r m) where
96+instance HasCliConfig e m => HasCliConfig e (ReaderT r m) where
87 getCliConfig = lift getCliConfig
97 getCliConfig = lift getCliConfig
88
98
89−instance (Monoid w, HasCliConfig m) => HasCliConfig (WriterT w m) where
99+instance (Monoid w, HasCliConfig e m) => HasCliConfig e (WriterT w m) where
90 getCliConfig = lift getCliConfig
100 getCliConfig = lift getCliConfig
91
101
92−instance HasCliConfig m => HasCliConfig (StateT s m) where
102+instance HasCliConfig e m => HasCliConfig e (StateT s m) where
93 getCliConfig = lift getCliConfig
103 getCliConfig = lift getCliConfig
94
104
95−instance HasCliConfig m => HasCliConfig (ExceptT e m) where
105+instance HasCliConfig e m => HasCliConfig e (ExceptT e m) where
96 getCliConfig = lift getCliConfig
106 getCliConfig = lift getCliConfig
97
107
98--------------------------------------------------------------------------------
108--------------------------------------------------------------------------------
99
109
100−newtype CliT m a = CliT
110+newtype CliT e m a = CliT
101− { unCliT :: ReaderT CliConfig (DieT m) a
111+ { unCliT :: ReaderT (CliConfig e) (DieT e m) a
102 }
112 }
103 deriving
113 deriving
104 ( Functor, Applicative, Monad, MonadIO
114 ( Functor, Applicative, Monad, MonadIO
105 , MonadThrow, MonadCatch, MonadMask
115 , MonadThrow, MonadCatch, MonadMask
116+ , MonadLog Output -- CliLog
117+ , MonadError e -- CliThrow
106− , MonadLog Output, MonadError Text, MonadReader CliConfig
118+ , MonadReader (CliConfig e) -- HasCliConfig
107 )
119 )
108
120
109−instance MonadTrans CliT where
121+instance MonadTrans (CliT e) where
110 lift = CliT . lift . lift
122 lift = CliT . lift . lift
111
123
112−instance Monad m => HasCliConfig (CliT m) where
124+instance Monad m => HasCliConfig e (CliT e m)where
113 getCliConfig = ask
125 getCliConfig = ask
lib/command/obelisk-command.cabal+1−3
@@ -15,7 +15,6 @@ library
15 , binary
15 , binary
16 , bytestring
16 , bytestring
17 , obelisk-cliapp
17 , obelisk-cliapp
18− , obelisk-migration
19 , containers
18 , containers
20 , data-default
19 , data-default
21 , directory
20 , directory
@@ -32,6 +31,7 @@ library
32 , modern-uri
31 , modern-uri
33 , monad-loops
32 , monad-loops
34 , mtl
33 , mtl
34+ , megaparsec
35 , network
35 , network
36 , network-uri
36 , network-uri
37 , optparse-applicative
37 , optparse-applicative
@@ -52,8 +52,6 @@ library
52 Obelisk.Command.Project
52 Obelisk.Command.Project
53 Obelisk.Command.Run
53 Obelisk.Command.Run
54 Obelisk.Command.Thunk
54 Obelisk.Command.Thunk
55− Obelisk.Command.Upgrade
56− Obelisk.Command.Upgrade.Hash
57 Obelisk.Command.Utils
55 Obelisk.Command.Utils
58 Obelisk.Command.VmBuilder
56 Obelisk.Command.VmBuilder
59 -- -fobject-code is so that the StaticPointers extension can work in ghci
57 -- -fobject-code is so that the StaticPointers extension can work in ghci
lib/command/src/Obelisk/App.hs+47−7
@@ -2,11 +2,15 @@
2{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleInstances #-}
3{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5+{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE MultiParamTypeClasses #-}
6{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE StandaloneDeriving #-}
8{-# LANGUAGE StandaloneDeriving #-}
9+{-# LANGUAGE TemplateHaskell #-}
10+{-# LANGUAGE TupleSections #-}
8module Obelisk.App where
11module Obelisk.App where
9
12
13+import Control.Lens
10import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow)
14import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow)
11import Control.Monad.Reader (MonadIO, ReaderT (..), ask, runReaderT)
15import Control.Monad.Reader (MonadIO, ReaderT (..), ask, runReaderT)
12import Control.Monad.Writer (WriterT)
16import Control.Monad.Writer (WriterT)
@@ -17,18 +21,50 @@ import Data.Text (Text)
17import System.Directory (XdgDirectory (XdgData), getXdgDirectory)
21import System.Directory (XdgDirectory (XdgData), getXdgDirectory)
18import Control.Monad.Log (MonadLog)
22import Control.Monad.Log (MonadLog)
19
23
20−import Obelisk.CliApp (CliConfig, CliLog, CliThrow, CliT (..), HasCliConfig, runCli, Output)
24+import Obelisk.CliApp
25+ ( CliConfig
26+ , CliLog
27+ , CliThrow
28+ , CliT (..)
29+ , ProcessFailure
30+ , AsProcessFailure (..)
31+ , AsUnstructuredError (..)
32+ , HasCliConfig
33+ , Output
34+ , runCli
35+ )
36+
37+data ObeliskError
38+ = ObeliskError_ProcessError
39+ { obeliskError_err :: ProcessFailure
40+ , obeliskError_mAnn :: Maybe Text
41+ }
42+ | ObeliskError_Unstructured Text
43+
44+makePrisms ''ObeliskError
45+
46+instance AsUnstructuredError ObeliskError where
47+ asUnstructuredError = _ObeliskError_Unstructured
48+
49+-- Only project when the other field is null, otherwise we are not law abiding.
50+instance AsProcessFailure ObeliskError where
51+ asProcessFailure = _ObeliskError_ProcessError . prism (, Nothing) f
52+ where f = \case
53+ (pf, Nothing) -> Right pf
54+ pann@(_, Just _) -> Left pann
21
55
22newtype Obelisk = Obelisk
56newtype Obelisk = Obelisk
23− { _obelisk_cliConfig :: CliConfig
57+ { _obelisk_cliConfig :: CliConfig ObeliskError
24 }
58 }
25
59
26newtype ObeliskT m a = ObeliskT
60newtype ObeliskT m a = ObeliskT
27− { unObeliskT :: ReaderT Obelisk (CliT m) a
61+ { unObeliskT :: ReaderT Obelisk (CliT ObeliskError m) a
28 }
62 }
29 deriving
63 deriving
30 ( Functor, Applicative, Monad, MonadIO, MonadThrow, MonadCatch, MonadMask
64 ( Functor, Applicative, Monad, MonadIO, MonadThrow, MonadCatch, MonadMask
31− , MonadLog Output, MonadError Text, HasCliConfig)
65+ , MonadLog Output -- CliLog
66+ , MonadError ObeliskError -- CliThrow ObeliskError
67+ , HasCliConfig ObeliskError)
32
68
33instance MonadTrans ObeliskT where
69instance MonadTrans ObeliskT where
34 lift = ObeliskT . lift . lift
70 lift = ObeliskT . lift . lift
@@ -57,14 +93,18 @@ runObelisk c =
57 . flip runReaderT c
93 . flip runReaderT c
58 . unObeliskT
94 . unObeliskT
59
95
60−type MonadObelisk m =
96+type MonadInfallibleObelisk m =
61 ( CliLog m
97 ( CliLog m
62− , CliThrow m
63− , HasCliConfig m
98+ , HasCliConfig ObeliskError m
64 , HasObelisk m
99 , HasObelisk m
65 , MonadIO m
100 , MonadIO m
66 , MonadMask m
101 , MonadMask m
67 )
102 )
68
103
104+type MonadObelisk m =
105+ ( MonadInfallibleObelisk m
106+ , CliThrow ObeliskError m
107+ )
108+
69getObeliskUserStateDir :: IO FilePath
109getObeliskUserStateDir :: IO FilePath
70getObeliskUserStateDir = getXdgDirectory XdgData "obelisk"
110getObeliskUserStateDir = getXdgDirectory XdgData "obelisk"
lib/command/src/Obelisk/Command.hs+44−112
@@ -8,15 +8,13 @@
8module Obelisk.Command where
8module Obelisk.Command where
9
9
10import Control.Monad
10import Control.Monad
11−import Control.Monad.Catch (catch)
12import Control.Monad.IO.Class (liftIO)
11import Control.Monad.IO.Class (liftIO)
13import qualified Data.Binary as Binary
12import qualified Data.Binary as Binary
14import Data.Bool (bool)
13import Data.Bool (bool)
15import qualified Data.ByteString.Base16 as Base16
14import qualified Data.ByteString.Base16 as Base16
16import qualified Data.ByteString.Lazy as LBS
15import qualified Data.ByteString.Lazy as LBS
17import Data.List
16import Data.List
18−import Data.Maybe (catMaybes, listToMaybe)
17+import Data.Maybe (catMaybes)
19−import Data.Text (Text)
20import qualified Data.Text as T
18import qualified Data.Text as T
21import Data.Text.Encoding
19import Data.Text.Encoding
22import GHC.StaticPtr
20import GHC.StaticPtr
@@ -35,11 +33,8 @@ import Obelisk.Command.Deploy
35import Obelisk.Command.Project
33import Obelisk.Command.Project
36import Obelisk.Command.Run
34import Obelisk.Command.Run
37import Obelisk.Command.Thunk
35import Obelisk.Command.Thunk
38−import Obelisk.Command.Upgrade
39−import Obelisk.Command.Upgrade.Hash (getDirectoryHash, getHashAtGitRevision)
40import Obelisk.Command.Utils
36import Obelisk.Command.Utils
41import qualified Obelisk.Command.VmBuilder as VmBuilder
37import qualified Obelisk.Command.VmBuilder as VmBuilder
42−import Obelisk.Migration (Hash)
43
38
44
39
45data Args = Args
40data Args = Args
@@ -96,16 +91,11 @@ data ObCommand
96 | ObCommand_Thunk ThunkCommand
91 | ObCommand_Thunk ThunkCommand
97 | ObCommand_Repl
92 | ObCommand_Repl
98 | ObCommand_Watch
93 | ObCommand_Watch
99− | ObCommand_Upgrade (Maybe Text)
100 | ObCommand_Internal ObInternal
94 | ObCommand_Internal ObInternal
101 deriving Show
95 deriving Show
102
96
103data ObInternal
97data ObInternal
104 = ObInternal_RunStaticIO StaticKey
98 = ObInternal_RunStaticIO StaticKey
105− | ObInternal_Hash (Maybe Text)
106− | ObInternal_CreateMigration
107− | ObInternal_VerifyMigration
108− | ObInternal_Migrate Hash
109 | ObInternal_CLIDemo
99 | ObInternal_CLIDemo
110 deriving Show
100 deriving Show
111
101
@@ -136,7 +126,6 @@ obCommand cfg = hsubparser
136 , command "thunk" $ info (ObCommand_Thunk <$> thunkCommand) $ progDesc "Manipulate thunk directories"
126 , command "thunk" $ info (ObCommand_Thunk <$> thunkCommand) $ progDesc "Manipulate thunk directories"
137 , command "repl" $ info (pure ObCommand_Repl) $ progDesc "Open an interactive interpreter"
127 , command "repl" $ info (pure ObCommand_Repl) $ progDesc "Open an interactive interpreter"
138 , command "watch" $ info (pure ObCommand_Watch) $ progDesc "Watch current project for errors and warnings"
128 , command "watch" $ info (pure ObCommand_Watch) $ progDesc "Watch current project for errors and warnings"
139− , command "upgrade" $ info (ObCommand_Upgrade <$> argument (maybeReader $ Just . Just . T.pack) (action "branch" <> metavar "GITBRANCH" <> value Nothing <> help "Git branch of obelisk to update to (defaults to the thunk's branch)")) $ progDesc "Upgrade Obelisk in the project"
140 ])
129 ])
141 <|> subparser
130 <|> subparser
142 (mconcat
131 (mconcat
@@ -182,7 +171,6 @@ deployInitOpts = DeployInitOpts
182 <*> strOption (long "route" <> metavar "PUBLICROUTE" <> help "Publicly accessible URL of your app")
171 <*> strOption (long "route" <> metavar "PUBLICROUTE" <> help "Publicly accessible URL of your app")
183 <*> strOption (long "admin-email" <> metavar "ADMINEMAIL" <> help "Email address where administrative alerts will be sent")
172 <*> strOption (long "admin-email" <> metavar "ADMINEMAIL" <> help "Email address where administrative alerts will be sent")
184 <*> flag True False (long "disable-https" <> help "Disable automatic https configuration for the backend")
173 <*> flag True False (long "disable-https" <> help "Disable automatic https configuration for the backend")
185− <*> strOption (long "upstream" <> value "origin" <> metavar "REMOTE" <> help "git remote to use for the src thunk" <> showDefault)
186
174
187type TeamID = String
175type TeamID = String
188data PlatformDeployment = Android | IOS TeamID
176data PlatformDeployment = Android | IOS TeamID
@@ -205,17 +193,12 @@ data DeployInitOpts = DeployInitOpts
205 , _deployInitOpts_route :: String
193 , _deployInitOpts_route :: String
206 , _deployInitOpts_adminEmail :: String
194 , _deployInitOpts_adminEmail :: String
207 , _deployInitOpts_enableHttps :: Bool
195 , _deployInitOpts_enableHttps :: Bool
208− , _deployInitOpts_remote :: String
209 }
196 }
210 deriving Show
197 deriving Show
211
198
212internalCommand :: Parser ObInternal
199internalCommand :: Parser ObInternal
213internalCommand = subparser $ mconcat
200internalCommand = subparser $ mconcat
214 [ command "run-static-io" $ info (ObInternal_RunStaticIO <$> argument (eitherReader decodeStaticKey) (action "static-key")) mempty
201 [ command "run-static-io" $ info (ObInternal_RunStaticIO <$> argument (eitherReader decodeStaticKey) (action "static-key")) mempty
215− , command "hash" $ info (ObInternal_Hash <$> argument (maybeReader $ Just . Just . T.pack) (action "rev" <> metavar "GITREVISION" <> value Nothing <> help "Calculate for the specified git revision (defaults to working copy")) $ progDesc "Computes hash of working directory (or git revision)"
216− , command "create-migration" $ info (pure ObInternal_CreateMigration) mempty
217− , command "verify-migration" $ info (pure ObInternal_VerifyMigration) mempty
218− , command "migrate" $ info (ObInternal_Migrate <$> strArgument (action "fromHash" <> metavar "FROMHASH" <> help "Migrate from this hash")) $ progDesc "Perform a migrate from the given hash to HEAD of obelisk thunk"
219 , command "clidemo" $ info (pure ObInternal_CLIDemo) mempty
202 , command "clidemo" $ info (pure ObInternal_CLIDemo) mempty
220 ]
203 ]
221
204
@@ -227,32 +210,17 @@ thunkDirectoryParser = fmap (dropTrailingPathSeparator . normalise) . strArgumen
227 , help "Path to directory containing thunk data"
210 , help "Path to directory containing thunk data"
228 ]
211 ]
229
212
230−data ThunkPackOpts = ThunkPackOpts
231− { _thunkPackOpts_directory :: FilePath
232− , _thunkPackOpts_upstream :: String
233− }
234− deriving Show
235−
236data ThunkCommand
213data ThunkCommand
237 = ThunkCommand_Update [FilePath]
214 = ThunkCommand_Update [FilePath]
238 | ThunkCommand_Unpack [FilePath]
215 | ThunkCommand_Unpack [FilePath]
239− | ThunkCommand_Pack [ThunkPackOpts]
216+ | ThunkCommand_Pack [FilePath]
240 deriving Show
217 deriving Show
241
218
242−thunkPackOpts :: Parser ThunkPackOpts
243−thunkPackOpts = (ThunkPackOpts <$> thunkDirectoryParser <*>) . strOption $ mconcat
244− [ long "upstream"
245− , value "origin"
246− , metavar "REMOTE"
247− , help "Git remote that packed thunk will point to"
248− , showDefault
249− ]
250−
251thunkCommand :: Parser ThunkCommand
219thunkCommand :: Parser ThunkCommand
252thunkCommand = hsubparser $ mconcat
220thunkCommand = hsubparser $ mconcat
253 [ command "update" $ info (ThunkCommand_Update <$> some thunkDirectoryParser) $ progDesc "Update thunk to latest revision available"
221 [ command "update" $ info (ThunkCommand_Update <$> some thunkDirectoryParser) $ progDesc "Update thunk to latest revision available"
254 , command "unpack" $ info (ThunkCommand_Unpack <$> some thunkDirectoryParser) $ progDesc "Unpack thunk into git checkout of revision it points to"
222 , command "unpack" $ info (ThunkCommand_Unpack <$> some thunkDirectoryParser) $ progDesc "Unpack thunk into git checkout of revision it points to"
255− , command "pack" $ info (ThunkCommand_Pack <$> some thunkPackOpts) $ progDesc "Pack git checkout into thunk that points at given upstream"
223+ , command "pack" $ info (ThunkCommand_Pack <$> some thunkDirectoryParser) $ progDesc "Pack git checkout into thunk that points at the current branch's upstream"
256 ]
224 ]
257
225
258parserPrefs :: ParserPrefs
226parserPrefs :: ParserPrefs
@@ -270,7 +238,22 @@ mkObeliskConfig = do
270 -- This function should not use argument parser (full argument parsing happens post handoff)
238 -- This function should not use argument parser (full argument parsing happens post handoff)
271 let logLevel = toLogLevel $ "-v" `elem` cliArgs
239 let logLevel = toLogLevel $ "-v" `elem` cliArgs
272 notInteractive <- not <$> isInteractiveTerm
240 notInteractive <- not <$> isInteractiveTerm
241+-- instance MonadIO m => MonadError (Either Text ProcessFailed) (DieT m) where
242+-- throwError = \case
243+-- Left s -> do
244+-- putLog Alert s
245+-- liftIO $ exitWith $ ExitFailure 2
246+-- Right (ProcessFailed p code) -> do
247+-- putLog Alert $ "Process exited with code " <> T.pack (show code) <> "; " <> T.pack (show p)
248+-- liftIO $ exitWith $ ExitFailure 2
273− cliConf <- newCliConfig logLevel notInteractive notInteractive
249+ cliConf <- newCliConfig logLevel notInteractive notInteractive $ \case
250+ ObeliskError_ProcessError (ProcessFailure p code) ann ->
251+ ( "Process exited with code " <> T.pack (show code) <> "; " <> reconstructCommand p
252+ <> maybe "" ("\n\n" <>) ann
253+ , 2
254+ )
255+ ObeliskError_Unstructured msg -> (msg, 2)
256+
274 return $ Obelisk cliConf
257 return $ Obelisk cliConf
275 where
258 where
276 toLogLevel = bool Notice Debug
259 toLogLevel = bool Notice Debug
@@ -308,67 +291,29 @@ main' argsCfg = do
308 , "logging-level=" <> show logLevel
291 , "logging-level=" <> show logLevel
309 ]
292 ]
310
293
311− (mainWithHandOff argsCfg <=< parseHandoff) =<< liftIO getArgs
294+ --TODO: We'd like to actually use the parser to determine whether to hand off,
312− `catch`
295+ --but in the case where this implementation of 'ob' doesn't support all
313− \(ProcessFailed p code) -> failWith $ "Process exited with code " <> tshow code <> "; " <> tshow p
296+ --arguments being passed along, this could fail. For now, we don't bother
314−
297+ --with optparse-applicative until we've done the handoff.
315−-- Type representing the result of a handoff calculation.
298+ let go as = do
316−data HandOff m
299+ args' <- liftIO $ handleParseResult (execParserPure parserPrefs (argsInfo argsCfg) as)
317− = HandOff_Yes FilePath [String] -- Handoff immediately to the given impl with the given args
318− | HandOff_Decide (m Bool) FilePath [String] -- Handoff only if the action returns True
319− | HandOff_No [String] -- Do not handoff, and continue with the given args
320−
321−mainWithHandOff :: MonadObelisk m => ArgsConfig -> HandOff m -> m ()
322−mainWithHandOff argsCfg = \case
323− HandOff_Yes impl as -> do
324− putLog Debug $ "Handing off to project obelisk " <> T.pack impl
325− liftIO $ executeFile impl False ("--no-handoff" : as) Nothing
326− HandOff_Decide f impl as -> do
327− withSpinner' "Deciding whether to handoff"
328− (Just $ bool
329− "Continuing in ambient obelisk without handing off"
330− "Handed off to project obelisk") f >>= \case
331− True -> mainWithHandOff argsCfg $ HandOff_Yes impl as
332− False -> mainWithHandOff argsCfg $ HandOff_No as
333− HandOff_No as -> do
334− putLog Debug $ "Not handing off"
335− args' <- liftIO $ parseCLIArgs argsCfg as
336− warnIfExtraneousFlag args'
337− ob $ _args_command args'
338− where
339− warnIfExtraneousFlag a = case _args_noHandOffPassed a of
300+ case _args_noHandOffPassed args' of
340− False -> return ()
301+ False -> return ()
341− True -> putLog Warning $
342− "Ignoring unexpected --no-handoff (should only be passed once and as the first argument)"
302+ True -> putLog Warning "--no-handoff should only be passed once and as the first argument; ignoring"
343−
303+ ob $ _args_command args'
344−-- Handoff logic
345−parseHandoff :: MonadObelisk m => [String] -> m (HandOff m)
346−parseHandoff as' = case hasNoHandoff as' of
347− (True, as) ->
348− pure $ HandOff_No as
349− (False, as) -> findProjectObeliskCommand "." >>= \case
304+ handoffAndGo as = findProjectObeliskCommand "." >>= \case
350− Nothing -> do
305+ Nothing -> go as -- If not in a project, just run ourselves
351− putLog Debug "Not in a project; no need to hand off"
352− pure $ HandOff_No as
353− Just impl -> case getSubCommand as of
306+ Just impl -> do
354− Just "upgrade" ->
307+ -- Invoke the real implementation, using --no-handoff to prevent infinite recursion
355− pure $ HandOff_Decide (decideHandOffToProjectOb ".") impl as
308+ putLog Debug $ "Handing off to " <> T.pack impl
356− _ ->
309+ liftIO $ executeFile impl False ("--no-handoff" : myArgs) Nothing
357− pure $ HandOff_Yes impl as
310+ case myArgs of
358− where
359− getSubCommand = listToMaybe . filter (not . isPrefixOf "-")
360− hasNoHandoff = \case
361− "--no-handoff" : xs ->
362− -- If we've been told not to hand off, don't hand off
311+ "--no-handoff" : as -> go as -- If we've been told not to hand off, don't hand off
363− (True, xs)
364− x:xs
365− -- Otherwise bash completion would always hand-off even if the user isn't trying to
312+ a:as -- Otherwise bash completion would always hand-off even if the user isn't trying to
366− | "--bash-completion" `isPrefixOf` x && "--no-handoff" `elem` xs ->
313+ | "--bash-completion" `isPrefixOf` a
367− (True, x:xs)
314+ && "--no-handoff" `elem` as -> go (a:as)
368− | otherwise ->
315+ | otherwise -> handoffAndGo (a:as)
369− (False, x:xs)
316+ as -> handoffAndGo as
370− xs ->
371− (False, xs)
372
317
373ob :: MonadObelisk m => ObCommand -> m ()
318ob :: MonadObelisk m => ObCommand -> m ()
374ob = \case
319ob = \case
@@ -390,7 +335,7 @@ ob = \case
390 Right (ThunkData_Packed ptr) -> return ptr
335 Right (ThunkData_Packed ptr) -> return ptr
391 Right (ThunkData_Checkout (Just ptr)) -> return ptr
336 Right (ThunkData_Checkout (Just ptr)) -> return ptr
392 Right (ThunkData_Checkout Nothing) ->
337 Right (ThunkData_Checkout Nothing) ->
393− getThunkPtr' False root (T.pack $ _deployInitOpts_remote deployOpts)
338+ getThunkPtr' False root
394 let sshKeyPath = _deployInitOpts_sshKey deployOpts
339 let sshKeyPath = _deployInitOpts_sshKey deployOpts
395 hostname = _deployInitOpts_hostname deployOpts
340 hostname = _deployInitOpts_hostname deployOpts
396 route = _deployInitOpts_route deployOpts
341 route = _deployInitOpts_route deployOpts
@@ -411,28 +356,15 @@ ob = \case
411 ObCommand_Thunk tc -> case tc of
356 ObCommand_Thunk tc -> case tc of
412 ThunkCommand_Update thunks -> mapM_ updateThunkToLatest thunks
357 ThunkCommand_Update thunks -> mapM_ updateThunkToLatest thunks
413 ThunkCommand_Unpack thunks -> mapM_ unpackThunk thunks
358 ThunkCommand_Unpack thunks -> mapM_ unpackThunk thunks
414− ThunkCommand_Pack thunks -> forM_ thunks $ \(ThunkPackOpts dir upstream) -> packThunk dir (T.pack upstream)
359+ ThunkCommand_Pack thunks -> forM_ thunks packThunk
415 ObCommand_Repl -> runRepl
360 ObCommand_Repl -> runRepl
416 ObCommand_Watch -> inNixShell' $ static runWatch
361 ObCommand_Watch -> inNixShell' $ static runWatch
417− ObCommand_Upgrade branch -> do
418− upgradeObelisk "." branch
419 ObCommand_Internal icmd -> case icmd of
362 ObCommand_Internal icmd -> case icmd of
420 ObInternal_RunStaticIO k -> liftIO (unsafeLookupStaticPtr @(ObeliskT IO ()) k) >>= \case
363 ObInternal_RunStaticIO k -> liftIO (unsafeLookupStaticPtr @(ObeliskT IO ()) k) >>= \case
421 Nothing -> failWith $ "ObInternal_RunStaticIO: no such StaticKey: " <> T.pack (show k)
364 Nothing -> failWith $ "ObInternal_RunStaticIO: no such StaticKey: " <> T.pack (show k)
422 Just p -> do
365 Just p -> do
423 c <- getObelisk
366 c <- getObelisk
424 liftIO $ runObelisk c $ deRefStaticPtr p
367 liftIO $ runObelisk c $ deRefStaticPtr p
425− ObInternal_Hash revM -> do
426− hash <- case revM of
427− Nothing -> getDirectoryHash [migrationDirName] "."
428− Just rev -> fmap head $ getHashAtGitRevision [rev] [migrationDirName] "."
429− putLog Notice hash
430− ObInternal_CreateMigration ->
431− createMigrationEdgeFromHEAD "."
432− ObInternal_VerifyMigration ->
433− verifyMigration "."
434− ObInternal_Migrate fromHash ->
435− migrateObelisk "." fromHash
436 ObInternal_CLIDemo -> cliDemo
368 ObInternal_CLIDemo -> cliDemo
437
369
438--TODO: Clean up all the magic strings throughout this codebase
370--TODO: Clean up all the magic strings throughout this codebase
lib/command/src/Obelisk/Command/Deploy.hs+1−1
@@ -113,7 +113,7 @@ deployPush deployPath getNixBuilders = do
113 checkGitCleanStatus srcPath True >>= \case
113 checkGitCleanStatus srcPath True >>= \case
114 True -> do
114 True -> do
115 result <- build
115 result <- build
116− packThunk srcPath "origin" -- get upstream
116+ packThunk srcPath
117 return result
117 return result
118 False -> do
118 False -> do
119 _ <- failWith $ T.pack $ "ob deploy push: ensure " <> srcPath <> " has no pending changes and latest is pushed upstream."
119 _ <- failWith $ T.pack $ "ob deploy push: ensure " <> srcPath <> " has no pending changes and latest is pushed upstream."
lib/command/src/Obelisk/Command/Nix.hs+36−19
@@ -1,8 +1,12 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE ConstraintKinds #-}
1{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE LambdaCase #-}
4{-# LANGUAGE LambdaCase #-}
3{-# LANGUAGE MultiParamTypeClasses #-}
5{-# LANGUAGE MultiParamTypeClasses #-}
4{-# LANGUAGE OverloadedStrings #-}
6{-# LANGUAGE OverloadedStrings #-}
7+{-# LANGUAGE Rank2Types #-}
5{-# LANGUAGE ScopedTypeVariables #-}
8{-# LANGUAGE ScopedTypeVariables #-}
9+{-# LANGUAGE TypeApplications #-}
6module Obelisk.Command.Nix
10module Obelisk.Command.Nix
7 ( nixBuild
11 ( nixBuild
8 , withNixRemoteCheck
12 , withNixRemoteCheck
@@ -15,7 +19,9 @@ module Obelisk.Command.Nix
15 , strArg
19 , strArg
16 ) where
20 ) where
17
21
18−import Control.Monad.Catch (catch, throwM)
22+--import Control.Monad.Catch (catch, throwM)
23+import Control.Lens
24+import Control.Monad.Except (ExceptT, runExceptT, throwError)
19import Control.Monad.IO.Class (liftIO)
25import Control.Monad.IO.Class (liftIO)
20import Data.Bool (bool)
26import Data.Bool (bool)
21import Data.Default
27import Data.Default
@@ -26,7 +32,7 @@ import System.Directory
26import System.Environment
32import System.Environment
27import System.Process (proc)
33import System.Process (proc)
28
34
29−import Obelisk.App (MonadObelisk)
35+import Obelisk.App (MonadInfallibleObelisk, MonadObelisk, ObeliskError (..))
30import Obelisk.CliApp
36import Obelisk.CliApp
31
37
32-- | Where to put nix-build output
38-- | Where to put nix-build output
@@ -81,8 +87,11 @@ instance Default NixBuildConfig where
81
87
82nixBuild :: MonadObelisk m => NixBuildConfig -> m FilePath
88nixBuild :: MonadObelisk m => NixBuildConfig -> m FilePath
83nixBuild cfg = withSpinner' ("Running nix-build on " <> desc) (Just $ const $ "Built " <> desc) $ do
89nixBuild cfg = withSpinner' ("Running nix-build on " <> desc) (Just $ const $ "Built " <> desc) $ do
84− withNixRemoteCheck $ readProcessAndLogStderr Debug $ proc "nix-build" $ mconcat
90+ output <- withNixRemoteCheck $ readProcessAndLogStderr Debug $ proc "nix-build" $ mconcat
85 [[path], attrArg, args, outLink, buildersArg]
91 [[path], attrArg, args, outLink, buildersArg]
92+ -- Remove final newline that Nix appends
93+ Just (outPath, '\n') <- pure $ T.unsnoc output
94+ pure $ T.unpack outPath
86 where
95 where
87 path = _target_path $ _nixBuildConfig_target cfg
96 path = _target_path $ _nixBuildConfig_target cfg
88 attr = _target_attr $ _nixBuildConfig_target cfg
97 attr = _target_attr $ _nixBuildConfig_target cfg
@@ -103,19 +112,27 @@ nixBuild cfg = withSpinner' ("Running nix-build on " <> desc) (Just $ const $ "B
103-- tell the user what to do.
112-- tell the user what to do.
104--
113--
105-- Added: June, 2018. Consider removing this eventually.
114-- Added: June, 2018. Consider removing this eventually.
106−withNixRemoteCheck :: MonadObelisk m => m a -> m a
115+withNixRemoteCheck
116+ :: MonadObelisk m
117+ => (forall m'. MonadInfallibleObelisk m' => ExceptT ObeliskError m' a)
118+ -> m a
107−withNixRemoteCheck f = f `catch` \e@(ProcessFailed _ _) -> do
119+withNixRemoteCheck f = do
120+ status <- runExceptT f
121+ case status of
122+ Right a -> pure a
123+ Left e -> throwError =<< case matching asProcessFailure e of
124+ Left _ -> pure e
108− liftIO (lookupEnv "NIX_REMOTE") >>= \case
125+ Right pf -> liftIO (lookupEnv "NIX_REMOTE") >>= \case
109− Just _ -> throwM e
126+ Just _ -> pure e
110− Nothing -> liftIO (writable <$> getPermissions "/nix/var/nix/db") >>= \case
127+ Nothing -> liftIO (writable <$> getPermissions "/nix/var/nix/db") >>= \case
111− True -> throwM e
128+ True -> pure e
112− False -> do
129+ False -> pure $ ObeliskError_ProcessError pf $ Just $ T.unlines
113− putLog Error "!!! "
130+ [ "!!! "
114− putLog Error "!!! A nix command failed to run. You might need to set the NIX_REMOTE environment variable"
131+ , "!!! A nix command failed to run. You might need to set the NIX_REMOTE environment variable"
115− putLog Error "!!! to `daemon`. To do this, run the following before running obelisk:"
132+ , "!!! to `daemon`. To do this, run the following before running obelisk:"
116− putLog Error "!!! "
133+ , "!!! "
117− putLog Error "!!! export NIX_REMOTE=daemon"
134+ , "!!! export NIX_REMOTE=daemon"
118− putLog Error "!!! "
135+ , "!!! "
119− putLog Error "!!! For details, see https://github.com/NixOS/nixpkgs/issues/5713"
136+ , "!!! For details, see https://github.com/NixOS/nixpkgs/issues/5713"
120− putLog Error "!!! "
137+ , "!!! "
121− throwM e
138+ ]
lib/command/src/Obelisk/Command/Project.hs−1
@@ -48,7 +48,6 @@ obeliskSourceWithBranch branch = ThunkSource_GitHub $ GitHubSource
48 { _gitHubSource_owner = "obsidiansystems"
48 { _gitHubSource_owner = "obsidiansystems"
49 , _gitHubSource_repo = "obelisk"
49 , _gitHubSource_repo = "obelisk"
50 , _gitHubSource_branch = Just branch
50 , _gitHubSource_branch = Just branch
51− , _gitHubSource_private = False
52 }
51 }
53
52
54data InitSource
53data InitSource
lib/command/src/Obelisk/Command/Run.hs+1−1
@@ -112,7 +112,7 @@ parseCabalPackage dir = do
112 mapM_ (putLog Error) $ fmap (T.pack . show) errors
112 mapM_ (putLog Error) $ fmap (T.pack . show) errors
113 return Nothing
113 return Nothing
114
114
115−withUTF8FileContentsM :: (MonadIO m, HasCliConfig m) => FilePath -> (ByteString -> CliT IO a) -> m a
115+withUTF8FileContentsM :: (MonadIO m, HasCliConfig e m) => FilePath -> (ByteString -> CliT e IO a) -> m a
116withUTF8FileContentsM fp f = do
116withUTF8FileContentsM fp f = do
117 c <- getCliConfig
117 c <- getCliConfig
118 liftIO $ withUTF8FileContents fp $ runCli c . f . toUTF8BS
118 liftIO $ withUTF8FileContents fp $ runCli c . f . toUTF8BS
lib/command/src/Obelisk/Command/Thunk.hs+345−265
@@ -27,10 +27,13 @@ module Obelisk.Command.Thunk
27 , updateThunk
27 , updateThunk
28 , getThunkPtr
28 , getThunkPtr
29 , getThunkPtr'
29 , getThunkPtr'
30+ , parseGitUri
31+ , uriThunkPtr
30 ) where
32 ) where
31
33
32import Control.Applicative
34import Control.Applicative
33−import Control.Exception (displayException, throwIO, try)
35+import Control.Exception (displayException, try)
36+import Control.Lens.Indexed hiding ((<.>))
34import Control.Monad
37import Control.Monad
35import Control.Monad.Catch (handle)
38import Control.Monad.Catch (handle)
36import Control.Monad.Except
39import Control.Monad.Except
@@ -39,15 +42,14 @@ import qualified Data.Aeson as Aeson
39import Data.Aeson.Encode.Pretty
42import Data.Aeson.Encode.Pretty
40import qualified Data.Aeson.Types as Aeson
43import qualified Data.Aeson.Types as Aeson
41import qualified Data.ByteString.Lazy as LBS
44import qualified Data.ByteString.Lazy as LBS
42−import qualified Data.ByteString.Lazy.Char8 as LBSC
43import Data.Default
45import Data.Default
44−import Data.Either.Combinators (rightToMaybe)
46+import Data.Either.Combinators (fromRight', rightToMaybe)
45−import Data.Foldable
46import Data.Git.Ref (Ref)
47import Data.Git.Ref (Ref)
47import qualified Data.Git.Ref as Ref
48import qualified Data.Git.Ref as Ref
48import qualified Data.List as L
49import qualified Data.List as L
49import Data.List.NonEmpty (NonEmpty (..))
50import Data.List.NonEmpty (NonEmpty (..))
50import qualified Data.List.NonEmpty as NonEmpty
51import qualified Data.List.NonEmpty as NonEmpty
52+import Data.Map (Map)
51import qualified Data.Map as Map
53import qualified Data.Map as Map
52import Data.Maybe
54import Data.Maybe
53import Data.Set (Set)
55import Data.Set (Set)
@@ -57,12 +59,9 @@ import qualified Data.Text as T
57import Data.Text.Encoding
59import Data.Text.Encoding
58import qualified Data.Text.IO as T
60import qualified Data.Text.IO as T
59import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
61import Data.Time.Clock.POSIX (posixSecondsToUTCTime)
60−import Data.Yaml (parseMaybe, (.:))
62+import Data.Yaml (parseMaybe)
61−import qualified Data.Yaml as Yaml
62import GitHub
63import GitHub
63import GitHub.Data.Name
64import GitHub.Data.Name
64−import GitHub.Endpoints.Repos.Contents (archiveForR)
65−import Network.URI
66import Obelisk.Command.Nix
65import Obelisk.Command.Nix
67import System.Directory
66import System.Directory
68import System.FilePath
67import System.FilePath
@@ -70,6 +69,7 @@ import System.IO.Error
70import System.IO.Temp
69import System.IO.Temp
71import System.Posix (getSymbolicLinkStatus, modificationTime)
70import System.Posix (getSymbolicLinkStatus, modificationTime)
72import System.Process (proc)
71import System.Process (proc)
72+import Text.URI
73
73
74import Obelisk.App (MonadObelisk)
74import Obelisk.App (MonadObelisk)
75import Obelisk.CliApp
75import Obelisk.CliApp
@@ -112,97 +112,73 @@ data GitHubSource = GitHubSource
112 { _gitHubSource_owner :: Name Owner
112 { _gitHubSource_owner :: Name Owner
113 , _gitHubSource_repo :: Name Repo
113 , _gitHubSource_repo :: Name Repo
114 , _gitHubSource_branch :: Maybe (Name Branch)
114 , _gitHubSource_branch :: Maybe (Name Branch)
115− , _gitHubSource_private :: Bool
116 }
115 }
117 deriving (Show, Eq, Ord)
116 deriving (Show, Eq, Ord)
118
117
119data GitSource = GitSource
118data GitSource = GitSource
120 { _gitSource_url :: URI
119 { _gitSource_url :: URI
121− , _gitSource_branch :: Name Branch
120+ , _gitSource_branch :: Maybe (Name Branch)
122 , _gitSource_fetchSubmodules :: Bool
121 , _gitSource_fetchSubmodules :: Bool
123 }
122 }
124 deriving (Show, Eq, Ord)
123 deriving (Show, Eq, Ord)
125
124
125+-- | Convert a GitHub source to a regular Git source. Assumes no submodules.
126+forgetGithub :: Bool -> GitHubSource -> GitSource
127+forgetGithub useSsh s = GitSource
128+ { _gitSource_url = URI
129+ { uriScheme = Just $ fromRight' $ mkScheme $ if useSsh then "ssh" else "https"
130+ , uriAuthority = Right $ Authority
131+ { authUserInfo = UserInfo (fromRight' $ mkUsername "git") Nothing
132+ <$ guard useSsh
133+ , authHost = fromRight' $ mkHost "github.com"
134+ , authPort = Nothing
135+ }
136+ , uriPath = Just ( False
137+ , fromRight' . mkPathPiece <$>
138+ untagName (_gitHubSource_owner s)
139+ :| [ untagName (_gitHubSource_repo s) <> ".git" ]
140+ )
141+ , uriQuery = []
142+ , uriFragment = Nothing
143+ }
144+ , _gitSource_branch = _gitHubSource_branch s
145+ , _gitSource_fetchSubmodules = False
146+ }
147+
126getThunkGitBranch :: ThunkPtr -> Maybe Text
148getThunkGitBranch :: ThunkPtr -> Maybe Text
127getThunkGitBranch (ThunkPtr _ src) = fmap untagName $ case src of
149getThunkGitBranch (ThunkPtr _ src) = fmap untagName $ case src of
128 ThunkSource_GitHub s -> _gitHubSource_branch s
150 ThunkSource_GitHub s -> _gitHubSource_branch s
129− ThunkSource_Git s -> Just $ _gitSource_branch s
151+ ThunkSource_Git s -> _gitSource_branch s
130
152
131commitNameToRef :: Name Commit -> Ref
153commitNameToRef :: Name Commit -> Ref
132commitNameToRef (N c) = Ref.fromHex $ encodeUtf8 c
154commitNameToRef (N c) = Ref.fromHex $ encodeUtf8 c
133
155
134-- TODO: Use spinner here.
156-- TODO: Use spinner here.
135−getNixSha256ForUriUnpacked :: MonadObelisk m => URI -> m NixSha256
157+getNixSha256ForUriUnpacked
158+ :: MonadObelisk m
159+ => URI
160+ -> m NixSha256
136getNixSha256ForUriUnpacked uri =
161getNixSha256ForUriUnpacked uri =
137− withExitFailMessage ("nix-prefetch-url: Failed to determine sha256 hash of URL " <> T.pack (show uri)) $ do
162+ withExitFailMessage ("nix-prefetch-url: Failed to determine sha256 hash of URL " <> render uri) $ do
138− fmap T.pack $ withNixRemoteCheck $ readProcessAndLogStderr Debug $
163+ [hash] <- fmap T.lines $ withNixRemoteCheck $ readProcessAndLogOutput (Debug, Debug) $
139− proc "nix-prefetch-url" ["--unpack" , "--type" , "sha256" , show uri]
164+ proc "nix-prefetch-url" ["--unpack" , "--type" , "sha256" , T.unpack $ render uri]
165+ pure hash
140
166
141nixPrefetchGit :: MonadObelisk m => URI -> Text -> Bool -> m NixSha256
167nixPrefetchGit :: MonadObelisk m => URI -> Text -> Bool -> m NixSha256
142nixPrefetchGit uri rev fetchSubmodules =
168nixPrefetchGit uri rev fetchSubmodules =
143− withExitFailMessage ("nix-prefetch-git: Failed to determine sha256 hash of Git repo " <> T.pack (show uri) <> " at " <> rev) $ do
169+ withExitFailMessage ("nix-prefetch-git: Failed to determine sha256 hash of Git repo " <> render uri <> " at " <> rev) $ do
144 out <- withNixRemoteCheck $ readProcessAndLogStderr Debug $
170 out <- withNixRemoteCheck $ readProcessAndLogStderr Debug $
145 proc "nix-prefetch-git" $ filter (/="")
171 proc "nix-prefetch-git" $ filter (/="")
146− [ "--url", show uri
172+ [ "--url", T.unpack $ render uri
147 , "--rev", T.unpack rev
173 , "--rev", T.unpack rev
148 , if fetchSubmodules then "--fetch-submodules" else ""
174 , if fetchSubmodules then "--fetch-submodules" else ""
149 , "--quiet"
175 , "--quiet"
150 ]
176 ]
151
177
152− case parseMaybe (Aeson..: "sha256") =<< Aeson.decode (LBSC.pack out) of
178+ case parseMaybe (Aeson..: "sha256") =<< Aeson.decodeStrict (encodeUtf8 out) of
153− Nothing -> failWith $ "nix-prefetch-git: unrecognized output " <> T.pack out
179+ Nothing -> failWith $ "nix-prefetch-git: unrecognized output " <> out
154 Just x -> pure x
180 Just x -> pure x
155
181
156−getLatestGitRev :: MonadObelisk m => GitSource -> m ThunkRev
157−getLatestGitRev s = withSystemTempDirectory "git-clone" $ \tmpDir -> do
158− withExitFailMessage ("Unable to determine latest git revision for branch " <> branch) $ do
159− let git = fmap T.pack . readProcessAndLogStderr Debug . gitProc tmpDir
160− out <- liftA2 (<>)
161− (git ["clone", "--no-checkout", show $ _gitSource_url s]) -- Might be able to use --bare here instead to go faster.
162− (git ["log", T.unpack branch, "--max-count=1", "--format=%H"])
163−
164− case T.strip <$> safeLast (T.lines out) of
165− Nothing -> failWith $ "Unable to parse git log: " <> out
166− Just rev -> do
167− putLog Debug $ "Latest commit in " <> branch <> " is " <> rev
168− sha <- nixPrefetchGit (_gitSource_url s) rev (_gitSource_fetchSubmodules s)
169− putLog Debug $ "Nix sha256 is " <> sha
170− pure $ ThunkRev
171− { _thunkRev_commit = Ref.fromHexString $ T.unpack rev
172− , _thunkRev_nixSha256 = sha
173− }
174− where
175− remote :: Text = "origin"
176− branch :: Text = remote <> "/" <> untagName (_gitSource_branch s)
177−
178− safeLast [] = Nothing
179− safeLast xs = Just $ last xs
180−
181−-- | Get the latest revision available from the given source
182−getLatestRev :: MonadObelisk m => ThunkSource -> m ThunkRev
183−getLatestRev = \case
184− ThunkSource_GitHub s -> do
185− auth <- liftIO $ getHubAuth "github.com"
186− commitsResult <- liftIO $ executeRequestMaybe auth $ commitsWithOptionsForR
187− (_gitHubSource_owner s)
188− (_gitHubSource_repo s)
189− (FetchAtLeast 1)
190− $ case _gitHubSource_branch s of
191− Nothing -> []
192− Just b -> [CommitQuerySha $ untagName b]
193− commitInfos <- either (liftIO . throwIO) return commitsResult
194− commitInfo : _ <- return $ toList commitInfos
195− let commit = commitSha commitInfo
196− putLog Debug $ "Latest commit is " <> untagName commit
197− Right archiveUri <- liftIO $ executeRequestMaybe auth $ archiveForR (_gitHubSource_owner s) (_gitHubSource_repo s) ArchiveFormatTarball $ Just $ untagName commit
198− nixSha256 <- getNixSha256ForUriUnpacked archiveUri
199− putLog Debug $ "Nix sha256 is " <> nixSha256
200− return $ ThunkRev
201− { _thunkRev_commit = commitNameToRef commit
202− , _thunkRev_nixSha256 = nixSha256
203− }
204− ThunkSource_Git s -> getLatestGitRev s
205−
206--TODO: Pretty print these
182--TODO: Pretty print these
207data ReadThunkError
183data ReadThunkError
208 = ReadThunkError_UnrecognizedFiles
184 = ReadThunkError_UnrecognizedFiles
@@ -311,18 +287,16 @@ parseGitHubSource v = do
311 owner <- v Aeson..: "owner"
287 owner <- v Aeson..: "owner"
312 repo <- v Aeson..: "repo"
288 repo <- v Aeson..: "repo"
313 branch <- v Aeson..:! "branch"
289 branch <- v Aeson..:! "branch"
314− mPrivate <- v Aeson..:! "private"
315 pure $ GitHubSource
290 pure $ GitHubSource
316 { _gitHubSource_owner = owner
291 { _gitHubSource_owner = owner
317 , _gitHubSource_repo = repo
292 , _gitHubSource_repo = repo
318 , _gitHubSource_branch = branch
293 , _gitHubSource_branch = branch
319− , _gitHubSource_private = fromMaybe False mPrivate
320 }
294 }
321
295
322parseGitSource :: Aeson.Object -> Aeson.Parser GitSource
296parseGitSource :: Aeson.Object -> Aeson.Parser GitSource
323parseGitSource v = do
297parseGitSource v = do
324 Just url <- parseGitUri <$> v Aeson..: "url"
298 Just url <- parseGitUri <$> v Aeson..: "url"
325− branch <- v Aeson..: "branch"
299+ branch <- v Aeson..:! "branch"
326 fetchSubmodules <- v Aeson..:! "fetchSubmodules"
300 fetchSubmodules <- v Aeson..:! "fetchSubmodules"
327 pure $ GitSource
301 pure $ GitSource
328 { _gitSource_url = url
302 { _gitSource_url = url
@@ -351,20 +325,14 @@ encodeThunkPtrData (ThunkPtr rev src) = case src of
351 ThunkSource_GitHub s -> encodePretty' githubCfg $ Aeson.object $ catMaybes
325 ThunkSource_GitHub s -> encodePretty' githubCfg $ Aeson.object $ catMaybes
352 [ Just $ "owner" .= _gitHubSource_owner s
326 [ Just $ "owner" .= _gitHubSource_owner s
353 , Just $ "repo" .= _gitHubSource_repo s
327 , Just $ "repo" .= _gitHubSource_repo s
354− , case _gitHubSource_branch s of
328+ , ("branch" .=) <$> _gitHubSource_branch s
355− Just b -> Just $ "branch" .= b
356− Nothing -> Nothing
357− , if _gitHubSource_private s
358− then Just $ "private" .= True
359− else Nothing
360 , Just $ "rev" .= Ref.toHexString (_thunkRev_commit rev)
329 , Just $ "rev" .= Ref.toHexString (_thunkRev_commit rev)
361 , Just $ "sha256" .= _thunkRev_nixSha256 rev
330 , Just $ "sha256" .= _thunkRev_nixSha256 rev
362 ]
331 ]
363 ThunkSource_Git s -> encodePretty' plainGitCfg $ Aeson.object $ catMaybes
332 ThunkSource_Git s -> encodePretty' plainGitCfg $ Aeson.object $ catMaybes
364− --TODO: Is this safe? read/show is jank for `URI`
365− [ Just $ "url" .= show (_gitSource_url s)
333+ [ Just $ "url" .= render (_gitSource_url s)
366 , Just $ "rev" .= Ref.toHexString (_thunkRev_commit rev)
334 , Just $ "rev" .= Ref.toHexString (_thunkRev_commit rev)
367− , Just $ "branch" .= _gitSource_branch s
335+ , ("branch" .=) <$> _gitSource_branch s
368 , Just $ "sha256" .= _thunkRev_nixSha256 rev
336 , Just $ "sha256" .= _thunkRev_nixSha256 rev
369 , Just $ "fetchSubmodules" .= _gitSource_fetchSubmodules s
337 , Just $ "fetchSubmodules" .= _gitSource_fetchSubmodules s
370 ]
338 ]
@@ -496,20 +464,6 @@ plainGitStandaloneLoaderV2 = T.unlines
496thunkFileNames :: [FilePath]
464thunkFileNames :: [FilePath]
497thunkFileNames = ["default.nix", "github.json", "git.json"]
465thunkFileNames = ["default.nix", "github.json", "git.json"]
498
466
499−-- | Look for authentication info from the 'hub' command
500−getHubAuth
501− :: Text -- ^ Domain name
502− -> IO (Maybe Auth)
503−getHubAuth domain = do
504− hubConfig <- getXdgDirectory XdgConfig "hub"
505− Yaml.decodeFileEither hubConfig >>= \case
506− Left _ -> return Nothing
507− Right v -> return $ flip parseMaybe v $ \v' -> do
508− Yaml.Array domainConfigs <- v' .: domain --TODO: Determine what multiple domainConfigs means
509− [Yaml.Object domainConfig] <- return $ toList domainConfigs
510− token <- domainConfig .: "oauth_token"
511− return $ OAuth $ encodeUtf8 token
512−
513--TODO: when checking something out, make a shallow clone
467--TODO: when checking something out, make a shallow clone
514
468
515-- | Checks a cache directory to see if there is a fresh symlink
469-- | Checks a cache directory to see if there is a fresh symlink
@@ -588,7 +542,7 @@ updateThunk p f = withSystemTempDirectory "obelisk-thunkptr-" $ \tmpDir -> do
588 p' <- copyThunkToTmp tmpDir p
542 p' <- copyThunkToTmp tmpDir p
589 unpackThunk' True p'
543 unpackThunk' True p'
590 result <- f p'
544 result <- f p'
591− updateThunkFromTmp p' "origin" -- TODO: stop hardcoding remote
545+ updateThunkFromTmp p'
592 return result
546 return result
593 where
547 where
594 copyThunkToTmp tmpDir thunkDir = readThunk thunkDir >>= \case
548 copyThunkToTmp tmpDir thunkDir = readThunk thunkDir >>= \case
@@ -599,8 +553,8 @@ updateThunk p f = withSystemTempDirectory "obelisk-thunkptr-" $ \tmpDir -> do
599 proc "cp" ["-r", "-T", thunkDir, tmpThunk]
553 proc "cp" ["-r", "-T", thunkDir, tmpThunk]
600 return tmpThunk
554 return tmpThunk
601 Right _ -> failWith $ "Thunk is not packed"
555 Right _ -> failWith $ "Thunk is not packed"
602− updateThunkFromTmp p' remote = do
556+ updateThunkFromTmp p' = do
603− packThunk' True p' remote
557+ packThunk' True p'
604 callProcessAndLogOutput (Notice, Error) $
558 callProcessAndLogOutput (Notice, Error) $
605 proc "cp" ["-r", "-T", p', p]
559 proc "cp" ["-r", "-T", p', p]
606
560
@@ -619,190 +573,316 @@ unpackThunk' noTrail thunkDir = readThunk thunkDir >>= \case
619 let (thunkParent, thunkName) = splitFileName thunkDir
573 let (thunkParent, thunkName) = splitFileName thunkDir
620 withTempDirectory thunkParent thunkName $ \tmpRepo -> do
574 withTempDirectory thunkParent thunkName $ \tmpRepo -> do
621 let obGitDir = tmpRepo </> ".git" </> "obelisk"
575 let obGitDir = tmpRepo </> ".git" </> "obelisk"
622− case _thunkPtr_source tptr of
576+ s = case _thunkPtr_source tptr of
623− ThunkSource_GitHub s -> do
577+ ThunkSource_GitHub s' -> forgetGithub False s'
624− mauth <- liftIO $ getHubAuth "github.com"
625− repoResult <- liftIO $ executeRequestMaybe mauth $ repositoryR (_gitHubSource_owner s) (_gitHubSource_repo s)
626− githubURI <- either (liftIO . throwIO) (return . repoSshUrl) repoResult >>= \case
627− Nothing -> failWith "Cannot determine clone URI for thunk source"
628− Just c -> return $ T.unpack $ getUrl c
629−
630− withSpinner' ("Fetching thunk " <> T.pack thunkDir)
631− ( finalMsg noTrail $ const $ "Fetched thunk " <> T.pack thunkDir) $ do
632− callProcessAndLogOutput (Debug, Debug) $
633− proc "hub" ["clone", "-n", githubURI, tmpRepo]
634− --If this directory already exists then something is weird and we should fail
635− liftIO $ createDirectory obGitDir
636− callProcessAndLogOutput (Debug, Error) $
637− proc "cp" ["-r", "-T", thunkDir </> ".", obGitDir </> "orig-thunk"]
638−
639− -- Checkout
640− putLog Debug $ "Checking out " <> T.pack (show $ maybe "" untagName $ _gitHubSource_branch s)
641− callProcessAndLogOutput (Debug, Debug) $
642− proc "hub" $ concat
643− [ ["-C", tmpRepo]
644− , pure "checkout"
645− , maybe [] (\n -> ["-B", T.unpack (untagName n)]) (_gitHubSource_branch s)
646− , pure $ Ref.toHexString $ _thunkRev_commit $ _thunkPtr_rev tptr
647− ]
648− -- Set upstream branch
649− forM_ (_gitHubSource_branch s) $ \branch ->
650− callProcessAndLogOutput (Debug, Error) $
651− proc "hub" ["-C", tmpRepo, "branch", "-u", "origin/" <> T.unpack (untagName branch)]
652− callProcessAndLogOutput (Notice, Error) $ proc "rm" ["-r", thunkDir]
653− callProcessAndLogOutput (Notice, Error) $ proc "mv" ["-T", tmpRepo, thunkDir]
654−
655− ThunkSource_Git s -> do
578+ ThunkSource_Git s' -> s'
656− withSpinner' ("Fetching thunk " <> T.pack thunkName)
579+ withSpinner' ("Fetching thunk " <> T.pack thunkName)
657− (finalMsg noTrail $ const $ "Fetched thunk " <> T.pack thunkName) $ do
580+ (finalMsg noTrail $ const $ "Fetched thunk " <> T.pack thunkName) $ do
658− let git = callProcessAndLogOutput (Notice, Notice) . gitProc tmpRepo
581+ let git = callProcessAndLogOutput (Notice, Notice) . gitProc tmpRepo
582+ git $ [ "clone" ]
659− git ["clone", if _gitSource_fetchSubmodules s then "--recursive" else "", show (_gitSource_url s)]
583+ ++ ("--recursive" <$ guard (_gitSource_fetchSubmodules s))
584+ ++ [ T.unpack $ render $ _gitSource_url s ]
660− git ["reset", "--hard", Ref.toHexString $ _thunkRev_commit $ _thunkPtr_rev tptr]
585+ git ["reset", "--hard", Ref.toHexString $ _thunkRev_commit $ _thunkPtr_rev tptr]
661− when (_gitSource_fetchSubmodules s) $
586+ when (_gitSource_fetchSubmodules s) $
662− git ["submodule", "update", "--recursive", "--init"]
587+ git ["submodule", "update", "--recursive", "--init"]
663− git ["branch", "-u", "origin/" <> T.unpack (untagName $ _gitSource_branch s)]
588+ case _gitSource_branch s of
664−
589+ Just b -> git ["branch", "-u", "origin/" <> T.unpack (untagName $ b)]
590+ Nothing -> pure ()
591+
665− liftIO $ createDirectory obGitDir
592+ liftIO $ createDirectory obGitDir
666− callProcessAndLogOutput (Notice, Error) $
593+ callProcessAndLogOutput (Notice, Error) $
667− proc "cp" ["-r", "-T", thunkDir </> ".", obGitDir </> "orig-thunk"]
594+ proc "cp" ["-r", "-T", thunkDir </> ".", obGitDir </> "orig-thunk"]
668− callProcessAndLogOutput (Notice, Error) $
595+ callProcessAndLogOutput (Notice, Error) $
669− proc "rm" ["-r", thunkDir]
596+ proc "rm" ["-r", thunkDir]
670− callProcessAndLogOutput (Notice, Error) $
597+ callProcessAndLogOutput (Notice, Error) $
671− proc "mv" ["-T", tmpRepo, thunkDir]
598+ proc "mv" ["-T", tmpRepo, thunkDir]
672
599
673--TODO: add force mode to pack even if changes are present
600--TODO: add force mode to pack even if changes are present
674--TODO: add a rollback mode to pack to the original thunk
601--TODO: add a rollback mode to pack to the original thunk
675−packThunk :: MonadObelisk m => FilePath -> Text -> m ()
602+packThunk :: MonadObelisk m => FilePath -> m ()
676packThunk = packThunk' False
603packThunk = packThunk' False
677
604
678−packThunk' :: MonadObelisk m => Bool -> FilePath -> Text -> m ()
605+packThunk' :: MonadObelisk m => Bool -> FilePath -> m ()
679−packThunk' noTrail thunkDir upstream = readThunk thunkDir >>= \case
606+packThunk' noTrail thunkDir = readThunk thunkDir >>= \case
680 Left err -> failWith $ T.pack $ "thunk pack: " <> show err
607 Left err -> failWith $ T.pack $ "thunk pack: " <> show err
681 Right (ThunkData_Packed _) -> failWith "pack: thunk is already packed"
608 Right (ThunkData_Packed _) -> failWith "pack: thunk is already packed"
682 Right (ThunkData_Checkout _) -> do
609 Right (ThunkData_Checkout _) -> do
683 withSpinner' ("Packing thunk " <> T.pack thunkDir)
610 withSpinner' ("Packing thunk " <> T.pack thunkDir)
684 (finalMsg noTrail $ const $ "Packed thunk " <> T.pack thunkDir) $ do
611 (finalMsg noTrail $ const $ "Packed thunk " <> T.pack thunkDir) $ do
685− thunkPtr <- getThunkPtr thunkDir upstream
612+ thunkPtr <- getThunkPtr thunkDir
686 callProcessAndLogOutput (Debug, Error) $ proc "rm" ["-rf", thunkDir]
613 callProcessAndLogOutput (Debug, Error) $ proc "rm" ["-rf", thunkDir]
687 liftIO $ createThunk thunkDir thunkPtr
614 liftIO $ createThunk thunkDir thunkPtr
688
615
689−getThunkPtr :: MonadObelisk m => FilePath -> Text -> m ThunkPtr
616+getThunkPtr :: MonadObelisk m => FilePath -> m ThunkPtr
690getThunkPtr = getThunkPtr' True
617getThunkPtr = getThunkPtr' True
691
618
692−getThunkPtr' :: MonadObelisk m => Bool -> FilePath -> Text -> m ThunkPtr
619+getThunkPtr' :: forall m. MonadObelisk m => Bool -> FilePath -> m ThunkPtr
693−getThunkPtr' checkClean thunkDir upstream = do
620+getThunkPtr' checkClean thunkDir = do
694− when checkClean $ ensureCleanGitRepo thunkDir True $
621+ when checkClean $ ensureCleanGitRepo thunkDir True $
695− "thunk pack: thunk checkout contains unsaved modifications"
622+ "thunk pack: thunk checkout contains unsaved modifications"
696−
623+
697− -- Check whether there are any stashes
624+ -- Check whether there are any stashes
698− stashOutput <- readGitProcess thunkDir ["stash", "list"]
625+ stashOutput <- readGitProcess thunkDir ["stash", "list"]
699− when checkClean $ case T.null stashOutput of
626+ when checkClean $ case T.null stashOutput of
700− False -> do
627+ False -> do
701− failWith $ T.unlines $
628+ failWith $ T.unlines $
702− [ "thunk pack: thunk checkout has stashes"
629+ [ "thunk pack: thunk checkout has stashes"
703− , "git stash list:"
630+ , "git stash list:"
704− ] ++ T.lines stashOutput
631+ ] ++ T.lines stashOutput
705− True -> return ()
632+ True -> return ()
706−
633+
707− --Check whether all local heads are pushed
634+ -- Get information on all branches and their (optional) designated upstream
635+ -- correspondents
708− repoHeads <- T.lines <$> readGitProcess thunkDir ["for-each-ref", "--format=%(refname:short)", "refs/heads/"]
636+ (headDump :: [Text]) <- T.lines <$> readGitProcess thunkDir
709− remotes <- T.lines <$> readGitProcess thunkDir ["remote"]
637+ [ "for-each-ref"
710− --Check that the upstream specified actually exists
638+ , "--format=%(refname:short) %(upstream:short) %(upstream:remotename)"
711− case L.find (== upstream) remotes of
639+ , "refs/heads/"
712− Nothing -> failWith $ "thunk pack: upstream " <> upstream <> " does not exist. Available upstreams are " <> T.intercalate ", " remotes
640+ ]
713− Just _ -> return ()
641+
714− -- iterate over cartesian product
642+ (headInfo :: Map Text (Maybe (Text, Text)))
643+ <- fmap Map.fromList $ forM headDump $ \line -> do
644+ (branch : restOfLine) <- pure $ T.words line
645+ mUpstream <- case restOfLine of
646+ [] -> pure Nothing
647+ [u, r] -> pure $ Just (u, r)
648+ (_:_) -> failWith "git for-each-ref invalid output"
649+ pure (branch, mUpstream)
650+
651+ putLog Debug $ "branches: " <> T.pack (show headInfo)
652+
653+ let errorMap :: Map Text ()
654+ headUpstream :: Map Text (Text, Text)
655+ (errorMap, headUpstream) = flip Map.mapEither headInfo $ \case
656+ Nothing -> Left ()
657+ Just b -> Right b
658+
659+ putLog Debug $ "branches with upstream branch set: " <> T.pack (show headUpstream)
660+
661+ -- Check that every branch has a remote equivalent
715− when checkClean $ forM_ repoHeads $ \hd -> do
662+ when checkClean $ do
716− [localRev] <- T.lines <$> readGitProcess thunkDir ["rev-parse", T.unpack hd]
663+ let untrackedBranches = Map.keys errorMap
717− forM_ remotes $ \rm -> do
664+ when (not $ L.null untrackedBranches) $ failWith $ T.unlines $
718− --TODO: The error you get if a branch isn't pushed anywhere could be made more user friendly
665+ [ "thunk pack: Certain branches in the thunk have no upstream branch \
719− [remoteMergeRev] <- fmap T.lines $ readGitProcess thunkDir
666+ \set. This means don't know to check whether all your work is \
720− ["merge-base", T.unpack localRev, "remotes/" <> T.unpack rm <> "/" <> T.unpack hd]
667+ \saved. The offending branches are:"
721− case remoteMergeRev == localRev of
668+ , ""
722− False -> failWith $ mconcat [ "thunk unpack: branch ", hd, " has not been pushed to ", rm ]
669+ , T.unwords untrackedBranches
723− True -> return ()
670+ , ""
724−
671+ , "To fix this, you probably want to do:"
672+ , ""
673+ ] ++
674+ ((\branch -> "git push -u origin " <> branch) <$> untrackedBranches) ++
675+ [ ""
676+ , "These will push the branches to the default remote under the same \
677+ \name, and (thanks to the `-u`) remember that choice so you don't \
678+ \get this error again."
679+ ]
680+
681+ -- loosely by https://stackoverflow.com/questions/7773939/show-git-ahead-and-behind-info-for-all-branches-including-remotes
682+ stats <- iforM headUpstream $ \branch (upstream, _remote) -> do
683+ (stat :: [Text]) <- T.lines <$> readGitProcess thunkDir
684+ [ "rev-list", "--left-right"
685+ , T.unpack branch <> "..." <> T.unpack upstream
686+ ]
687+ let ahead = length $ [ () | Just ('<', _) <- T.uncons <$> stat ]
688+ behind = length $ [ () | Just ('>', _) <- T.uncons <$> stat ]
689+ pure (upstream, (ahead, behind))
690+
691+ -- Those branches which have commits ahead of, i.e. not on, the upstream
692+ -- branch. Purely being behind is fine.
693+ let nonGood = Map.filter ((/= 0) . fst . snd) stats
694+
695+ when (not $ Map.null nonGood) $ failWith $ T.unlines $
696+ [ "thunk pack: Certain branches in the thunk have commits not yet pushed upstream:"
697+ , ""
698+ ] ++
699+ (flip map (Map.toList nonGood) $ \(branch, (upstream, (ahead, behind))) -> mconcat
700+ [" ", branch, " ahead: ", T.pack (show ahead), " behind: ", T.pack (show behind), " remote branch ", upstream]) ++
701+ [ ""
702+ , "Please push these upstream and try again. (Or just fetch, if they are somehow \
703+ \pushed but this repo's remote tracking branches don't know it.)"
704+ ]
705+
725− --We assume it's safe to pack the thunk at this point
706+ -- We assume it's safe to pack the thunk at this point
707+ putLog Informational $ "All changes safe in git remotes. OK to pack thunk."
708+
709+ -- Get current branch ``
710+ mCurrentBranch <- listToMaybe
711+ <$> T.lines
712+ <$> readGitProcess thunkDir ["rev-parse", "--abbrev-ref", "HEAD"]
713+
714+ let remote = maybe "origin" snd $ flip Map.lookup headUpstream =<< mCurrentBranch
715+
726− [remoteUri'] <- fmap T.lines $ readGitProcess thunkDir ["config", "--get", "remote." <> T.unpack upstream <> ".url"]
716+ [remoteUri'] <- fmap T.lines $ readGitProcess thunkDir
727−
717+ [ "config"
718+ , "--get"
719+ , "remote." <> T.unpack remote <> ".url"
720+ ]
721+
722+ remoteUri <- case parseGitUri remoteUri' of
728− let uriParseFailure = "Could not identify git remote: " <> remoteUri'
723+ Nothing -> failWith $ "Could not identify git remote: " <> remoteUri'
729− mRemoteUri = parseGitUri remoteUri'
724+ Just uri -> pure uri
730− case mRemoteUri of
725+ uriThunkPtr remoteUri mCurrentBranch
731− Nothing -> failWith uriParseFailure
726+
732− Just remoteUri -> do
727+-- | Get the latest revision available from the given source
733− refs <- fmap (map (refsToTuples . T.words) . T.lines) $ readGitProcess thunkDir ["show-ref", "--head"]
728+getLatestRev :: MonadObelisk m => ThunkSource -> m ThunkRev
734− -- safe because exactly one hash is associated with HEAD
729+getLatestRev os = do
735− let Just currentHead = fst <$> L.find ((== "HEAD") . snd) refs
730+ let gitS = case os of
736− remoteHeads = Map.fromList $ catMaybes $ fmap
731+ ThunkSource_GitHub s -> forgetGithub False s
737− (\(x,y) -> (,) x <$> T.stripPrefix ("refs/remotes/" <> upstream <> "/") y)
732+ ThunkSource_Git s -> s
738− refs
733+ (_, commit) <- gitGetCommitBranch (_gitSource_url gitS) (untagName <$> _gitSource_branch gitS)
739− localHeads = Map.fromList $ catMaybes $ fmap
734+ case os of
740− (\(x,y) -> (,) x <$> T.stripPrefix "refs/heads/" y)
735+ ThunkSource_GitHub s -> githubThunkRev s commit
741− refs
736+ ThunkSource_Git s -> gitThunkRev s commit
742− currentUpstreamBranch = Map.lookup currentHead remoteHeads
737+
743− <|> Map.lookup currentHead localHeads
738+-- | Convert a URI to a thunk
744− if isGithubThunk remoteUri
739+--
745− then githubThunkPtr remoteUri currentHead currentUpstreamBranch
740+-- If the URL is a github URL, we try to just download an archive for
746− else gitThunkPtr remoteUri currentHead currentUpstreamBranch
741+-- performance. If that doesn't work (e.g. authentication issue), we fall back
747− where
742+-- on just doing things the normal way for git repos in general, and save it as
748− refsToTuples [x, y] = (x, y)
743+-- a regular git thunk.
749− refsToTuples x = error $ "thunk pack: cannot parse ref " <> show x
744+uriThunkPtr :: MonadObelisk m => URI -> Maybe Text -> m ThunkPtr
750− isGithubThunk u
745+uriThunkPtr uri mbranch = do
751− | Just uriAuth <- uriAuthority u
746+ (_, commit) <- gitGetCommitBranch uri mbranch
752− = case uriScheme u of
747+ (src, rev) <- case uriToThunkSource uri mbranch of
753− "ssh:" -> uriAuth == URIAuth "git@" "github.com" ""
748+ ThunkSource_GitHub s -> do
754− s -> s `L.elem` [ "git:", "https:", "http:" ] -- "http:" just redirects to "https:"
749+ rev <- runExceptT $ githubThunkRev s commit
755− && uriRegName uriAuth == "github.com"
750+ case rev of
756− | otherwise = False
751+ Right r -> pure (ThunkSource_GitHub s, r)
757− githubThunkPtr u commit' branch' = do
752+ Left e -> do
758− ["/", owner', repo'] <- return $ splitDirectories (uriPath u)
753+ putLog Warning $ "\
759− let owner = N (T.pack owner')
754+\Failed to fetch archive from GitHub. This is probably a private repo. \
760− dropGitExtension r = fromMaybe r $ T.stripSuffix ".git" r
755+\Falling back on normal fetchgit. Original failure:\n\n"
761− repo = N $ dropGitExtension $ T.pack repo'
756+ errorToWarning e
762− commit = N commit'
757+ let s' = forgetGithub True s
763− branch = N <$> branch'
758+ (,) (ThunkSource_Git s') <$> gitThunkRev s' commit
764− mauth <- liftIO $ getHubAuth "github.com"
759+ ThunkSource_Git s -> (,) (ThunkSource_Git s) <$> gitThunkRev s commit
765− repoResult <- liftIO $ executeRequestMaybe mauth $ repositoryR owner repo
760+ pure $ ThunkPtr
766− repoIsPrivate <- either (liftIO . throwIO) (return . repoPrivate) repoResult
761+ { _thunkPtr_rev = rev
767− archiveResult <- liftIO $ executeRequestMaybe mauth $
762+ , _thunkPtr_source = src
768− archiveForR owner repo ArchiveFormatTarball (Just (untagName commit))
763+ }
769− archiveUri <- either (liftIO . throwIO) return archiveResult
764+
770− hash <- getNixSha256ForUriUnpacked archiveUri
765+-- | N.B. Cannot infer all fields.
771− return $ ThunkPtr
766+--
772− { _thunkPtr_rev = ThunkRev
767+-- If the thunk is a GitHub thunk and fails, we do *not* fall back like with
773− { _thunkRev_commit = commitNameToRef commit
768+-- `uriThunkPtr`. Unlike a plain URL, a thunk src explicitly states which method
774− , _thunkRev_nixSha256 = hash
769+-- should be employed, and so we respect that.
775− }
770+uriToThunkSource :: URI -> Maybe Text -> ThunkSource
776− , _thunkPtr_source = ThunkSource_GitHub $ GitHubSource
771+uriToThunkSource u
777− { _gitHubSource_owner = owner
772+ | Right uriAuth <- uriAuthority u
778− , _gitHubSource_repo = repo
773+ , Just scheme <- unRText <$> uriScheme u
779− , _gitHubSource_branch = branch
774+ , case scheme of
780− , _gitHubSource_private = repoIsPrivate
775+ "ssh" -> uriAuth == Authority
781− }
776+ { authUserInfo = Just $ UserInfo (fromRight' $ mkUsername "git") Nothing
782− }
777+ , authHost = fromRight' $ mkHost "github.com"
783− gitThunkPtr u commit branch' = do
778+ , authPort = Nothing
784− let protocols = ["https:", "ssh:", "git:"]
785− unless (T.toLower (T.pack $ uriScheme u) `elem` protocols) $
786− failWith $ "thunk pack: obelisk currently only supports "
787− <> T.intercalate ", " protocols <> " protocols for non-GitHub remotes"
788− hash <- nixPrefetchGit u commit False
789− branch <- case branch' of
790− Nothing -> failWith "thunk pack: git thunks must track a branch"
791− Just b -> pure $ N b
792− pure $ ThunkPtr
793− { _thunkPtr_rev = ThunkRev
794− { _thunkRev_commit = commitNameToRef (N commit)
795− , _thunkRev_nixSha256 = hash
796− }
797− , _thunkPtr_source = ThunkSource_Git $ GitSource
798− { _gitSource_url = u
799− , _gitSource_branch = branch
800− , _gitSource_fetchSubmodules = False -- TODO: How do we determine if this should be true?
801 }
779 }
780+ s -> s `L.elem` [ "git", "https", "http" ] -- "http:" just redirects to "https:"
781+ && unRText (authHost uriAuth) == "github.com"
782+ , Just (_, owner :| [repoish]) <- uriPath u
783+ = \mbranch -> ThunkSource_GitHub $ GitHubSource
784+ { _gitHubSource_owner = N $ unRText owner
785+ , _gitHubSource_repo = N $ let
786+ repoish' = unRText repoish
787+ in case T.stripSuffix ".git" repoish' of
788+ Just repo -> repo
789+ Nothing -> repoish'
790+ , _gitHubSource_branch = N <$> mbranch
802− }
791+ }
792+
793+ | otherwise = \mbranch -> ThunkSource_Git $ GitSource
794+ { _gitSource_url = u
795+ , _gitSource_branch = N <$> mbranch
796+ , _gitSource_fetchSubmodules = False -- TODO: How do we determine if this should be true?
797+ }
798+
799+-- Funny signature indicates no effects depend on the optional branch name.
800+githubThunkRev
801+ :: forall m
802+ . MonadObelisk m
803+ => GitHubSource
804+ -> Text
805+ -> m ThunkRev
806+githubThunkRev s commit = do
807+ owner <- forcePP $ _gitHubSource_owner s
808+ repo <- forcePP $ _gitHubSource_repo s
809+ revTarball <- mkPathPiece $ commit <> ".tar.gz"
810+ let archiveUri = URI
811+ { uriScheme = Just $ fromRight' $ mkScheme "https"
812+ , uriAuthority = Right $ Authority
813+ { authUserInfo = Nothing
814+ , authHost = fromRight' $ mkHost "github.com"
815+ , authPort = Nothing
816+ }
817+ , uriPath = Just ( False
818+ , owner :| [ repo, fromRight' $ mkPathPiece "archive", revTarball ]
819+ )
820+ , uriQuery = []
821+ , uriFragment = Nothing
822+ }
823+ hash <- getNixSha256ForUriUnpacked archiveUri
824+ putLog Debug $ "Nix sha256 is " <> hash
825+ return $ ThunkRev
826+ { _thunkRev_commit = commitNameToRef $ N commit
827+ , _thunkRev_nixSha256 = hash
828+ }
829+ where
830+ forcePP :: Name entity -> m (RText 'PathPiece)
831+ forcePP = mkPathPiece . untagName
832+
833+gitThunkRev
834+ :: MonadObelisk m
835+ => GitSource
836+ -> Text
837+ -> m ThunkRev
838+gitThunkRev s commit = do
839+ let u = _gitSource_url s
840+ protocols = ["https", "ssh", "git"]
841+ Just scheme <- pure $ unRText <$> uriScheme u
842+ unless (T.toLower scheme `elem` protocols) $
843+ failWith $ "obelisk currently only supports "
844+ <> T.intercalate ", " protocols <> " protocols for non-GitHub remotes"
845+ hash <- nixPrefetchGit u commit $ _gitSource_fetchSubmodules s
846+ putLog Informational $ "Nix sha256 is " <> hash
847+ pure $ ThunkRev
848+ { _thunkRev_commit = commitNameToRef (N commit)
849+ , _thunkRev_nixSha256 = hash
850+ }
851+
852+-- | Given the URI to a git remote, and an optional branch name, return the name
853+-- of the branch along with the hash of the commit at tip of that branch.
854+--
855+-- If the branch name is passed in, it is returned exactly as-is. If it is not
856+-- passed it, the default branch of the repo is used instead.
857+gitGetCommitBranch
858+ :: MonadObelisk m => URI -> Maybe Text -> m (Text, CommitId)
859+gitGetCommitBranch uri mbranch = withExitFailMessage ("Failure for git remote " <> uriMsg) $ do
860+ bothMaps <- gitLsRemote
861+ (T.unpack $ render uri)
862+ (GitRef_Branch <$> mbranch)
863+ branch <- case mbranch of
864+ Nothing -> withExitFailMessage "Failed to find default branch" $ do
865+ b <- rethrowE $ gitLookupDefaultBranch bothMaps
866+ putLog Debug $ "Default branch for remote repo " <> uriMsg <> " is " <> b
867+ pure b
868+ Just b -> pure b
869+ commit <- rethrowE $ gitLookupCommitForRef bothMaps (GitRef_Branch branch)
870+ putLog Informational $ "Latest commit in branch " <> branch
871+ <> " from remote repo " <> uriMsg
872+ <> " is " <> commit
873+ pure (branch, commit)
874+ where
875+ rethrowE = either failWith pure
876+ uriMsg = render uri
803
877
804parseGitUri :: Text -> Maybe URI
878parseGitUri :: Text -> Maybe URI
805−parseGitUri x = parseURIReference (T.unpack x) <|> parseSshShorthand x
879+parseGitUri x = parseAbsoluteURI x <|> parseSshShorthand x
880+
881+parseAbsoluteURI :: Text -> Maybe URI
882+parseAbsoluteURI uri = do
883+ parsedUri <- mkURI uri
884+ guard $ isPathAbsolute parsedUri
885+ pure $ parsedUri
806
886
807parseSshShorthand :: Text -> Maybe URI
887parseSshShorthand :: Text -> Maybe URI
808parseSshShorthand uri = do
888parseSshShorthand uri = do
@@ -817,4 +897,4 @@ parseSshShorthand uri = do
817 -- This check is used to disambiguate a filepath containing a colon from shorthand
897 -- This check is used to disambiguate a filepath containing a colon from shorthand
818 guard $ isNothing (T.findIndex (=='/') authAndHostname)
898 guard $ isNothing (T.findIndex (=='/') authAndHostname)
819 && not (T.null colonAndPath)
899 && not (T.null colonAndPath)
820− parseURI $ T.unpack properUri
900+ mkURI properUri
lib/command/src/Obelisk/Command/Upgrade.hsdeleted−293
@@ -1,293 +0,0 @@
1−{-# LANGUAGE FlexibleContexts #-}
2−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3−{-# LANGUAGE LambdaCase #-}
4−{-# LANGUAGE MultiParamTypeClasses #-}
5−{-# LANGUAGE OverloadedStrings #-}
6−{-# LANGUAGE ScopedTypeVariables #-}
7−{-# LANGUAGE TypeApplications #-}
8−module Obelisk.Command.Upgrade where
9−
10−import Control.Monad (forM, unless, void)
11−import Control.Monad.Catch (onException)
12−import Control.Monad.Except
13−import Control.Monad.IO.Class (liftIO)
14−import Data.Maybe (catMaybes)
15−import Data.Monoid (Any (..), getAny)
16−import Data.Semigroup ((<>))
17−import qualified Data.Set as S
18−import Data.Text (Text)
19−import qualified Data.Text as T
20−import System.Directory
21−import System.FilePath
22−import System.Posix.Process (executeFile)
23−
24−import Obelisk.App (MonadObelisk)
25−import Obelisk.CliApp
26−import Obelisk.Command.Utils
27−
28−import Obelisk.Command.Project (toImplDir)
29−import Obelisk.Command.Project (findProjectObeliskCommand)
30−import Obelisk.Command.Thunk (ThunkData (..), getThunkGitBranch, readThunk, updateThunk)
31−
32−import Obelisk.Command.Upgrade.Hash
33−import Obelisk.Migration
34−
35−newtype HandOffAction = HandoffAction Any
36− deriving (Monoid, Semigroup, Ord, Eq, Show)
37−
38−instance Action HandOffAction where
39− parseEdgeMeta = HandoffAction . Any . (== "True")
40−
41−data MigrationGraph
42− = MigrationGraph_ObeliskUpgrade
43− | MigrationGraph_ObeliskHandoff
44− deriving (Eq, Show, Bounded, Enum)
45−
46−graphName :: MigrationGraph -> Text
47−graphName = \case
48− MigrationGraph_ObeliskHandoff -> "obelisk-handoff"
49− MigrationGraph_ObeliskUpgrade -> "obelisk-upgrade"
50−
51−fromGraphName :: Text -> MigrationGraph
52−fromGraphName = \case
53− "obelisk-handoff" -> MigrationGraph_ObeliskHandoff
54− "obelisk-upgrade" -> MigrationGraph_ObeliskUpgrade
55− _ -> error "Invalid graph name specified"
56−
57−graphNames :: [Text]
58−graphNames = fmap graphName $ [minBound .. maxBound]
59−
60−ensureCleanProject :: MonadObelisk m => FilePath -> m ()
61−ensureCleanProject project =
62− ensureCleanGitRepo project False "Cannot upgrade with uncommited changes"
63−
64−-- | Decide whether we (ambient ob) should handoff to project obelisk before performing upgrade
65−decideHandOffToProjectOb :: MonadObelisk m => FilePath -> m Bool
66−decideHandOffToProjectOb project = do
67− ensureCleanProject project
68− updateThunk (toImplDir project) $ \projectOb -> do
69− (ambientGraph, ambientHash) <- getAmbientObInfo
70− projectHash <- computeVertexHash projectOb
71− case hasVertex projectHash ambientGraph of
72− False -> do
73− putLog Warning "Project ob not found in ambient ob's migration graph; handing off anyway"
74− return True
75− True -> handleMigrationError (findPathAction ambientGraph projectHash ambientHash) >>= \case
76− Nothing -> do
77− putLog Warning "No migration path between project and ambient ob; handing off anyway"
78− return True
79− Just (HandoffAction dontHandoff) -> do
80− return $ not $ getAny dontHandoff
81− where
82− getAmbientObInfo = do
83− ambientOb <- getAmbientOb
84− getMigrationGraph' ambientOb MigrationGraph_ObeliskHandoff >>= \case
85− Nothing -> do
86− failWith "Ambient ob has no migration (this can't be possible)"
87− Just m -> do
88− -- We don't have ambient's ob source code, so locate its hash from the
89− -- graph. The last vertex should be it.
90− ambientHash <- handleMigrationError $ getLast (_migration_graph m)
91− return (m, ambientHash)
92−
93−-- | Return the path to the current ('ambient') obelisk process Nix directory
94−getAmbientOb :: MonadObelisk m => m FilePath
95−getAmbientOb = takeDirectory . takeDirectory <$> liftIO getObeliskExe
96−
97−upgradeObelisk :: MonadObelisk m => FilePath -> Maybe Text -> m ()
98−upgradeObelisk project gitBranchM = do
99− ensureCleanProject project
100− gitBranch <- maybe (getObeliskBranch project) pure gitBranchM
101− updateObelisk project gitBranch >>= handOffToNewOb project
102−
103−getObeliskBranch :: MonadObelisk m => FilePath -> m Text
104−getObeliskBranch project = readThunk (toImplDir project) >>= \case
105− Left e -> failWith $ T.pack $ show e
106− Right (ThunkData_Checkout _) -> failWith "obelisk thunk must be packed"
107− Right (ThunkData_Packed tptr) -> case getThunkGitBranch tptr of
108− Just v -> pure v
109− Nothing ->
110− failWith "You must run `ob upgrade` with the Git branch specified explicitly, as the project's obelisk thunk does not specify any."
111−
112−updateObelisk :: MonadObelisk m => FilePath -> Text -> m Hash
113−updateObelisk project gitBranch =
114− withSpinner ("Fetching new obelisk [" <> gitBranch <> "]") $
115− updateThunk (toImplDir project) $ \obImpl -> do
116− fromHash <- computeVertexHash obImpl
117− callProcessAndLogOutput (Debug, Debug) $
118− gitProc obImpl ["checkout", T.unpack gitBranch]
119− callProcessAndLogOutput (Debug, Debug) $
120− gitProc obImpl ["pull"]
121− return fromHash
122−
123−handOffToNewOb :: MonadObelisk m => FilePath -> Hash -> m ()
124−handOffToNewOb project fromHash = do
125− impl <- withSpinner' "Preparing for handoff" (Just $ ("Handed off to new obelisk " <>) . T.pack) $
126− findProjectObeliskCommand project >>= \case
127− Nothing -> failWith "Not an obelisk project"
128− Just impl -> pure impl
129− let opts = ["internal", "migrate", T.unpack fromHash]
130− liftIO $ executeFile impl False ("--no-handoff" : opts) Nothing
131−
132−migrateObelisk :: MonadObelisk m => FilePath -> Hash -> m ()
133−migrateObelisk project fromHash = void $ withSpinner' "Migrating to new obelisk" (Just id) $ do
134− updateThunk (toImplDir project) $ \obImpl -> revertObImplOnFail obImpl $ do
135− toHash <- computeVertexHash obImpl
136− g <- getMigrationGraph' obImpl MigrationGraph_ObeliskUpgrade >>= \case
137− Nothing -> failWith "New obelisk has no migration metadata"
138− Just m -> pure m
139−
140− unless (hasVertex fromHash g) $ do
141− failWith $ "Current obelisk hash " <> fromHash <> " missing in migration graph of new obelisk"
142− unless (hasVertex toHash g) $ do
143− -- This usually means that the target obelisk branch does not have
144− -- migration vertex for its latest commit; typically due to developer
145− -- negligence.
146− failWith $ "New obelisk hash " <> toHash <> " missing in its migration graph"
147−
148− if fromHash == toHash
149− then do
150− pure $ "No upgrade available (new Obelisk is the same)"
151− else do
152− putLog Debug $ "Migrating from " <> fromHash <> " to " <> toHash
153− handleMigrationError (findPathAction g fromHash toHash) >>= \case
154− Nothing -> do
155− failWith "Unable to find migration path"
156− Just action -> do
157− unless (action == mempty) $ do
158− putLog Notice "To upgrade your project to the new version of obelisk, please follow these instructions:\n"
159− putLog Notice action
160− pure $ "Migrated from " <> fromHash <> " to " <> toHash
161− where
162− revertObImplOnFail impl f = f `onException` do
163− putLog Notice $ T.pack $ "Reverting changes to " <> impl
164− callProcessAndLogOutput (Notice, Notice) $ gitProc project ["checkout", impl]
165−
166−-- | Get the migration graph for project
167−getMigrationGraph
168− :: (Action action, MonadObelisk m)
169− => FilePath -> MigrationGraph -> m (Migration action)
170−getMigrationGraph obDir graph = getMigrationGraph' obDir graph >>= \case
171− Nothing -> failWith "Migration graph missing"
172− Just m -> pure m
173−
174−getMigrationGraph'
175− :: (Action action, MonadObelisk m)
176− => FilePath -> MigrationGraph -> m (Maybe (Migration action))
177−getMigrationGraph' obDir graph = do
178− let name = graphName graph
179− dir = migrationDir obDir
180− putLog Debug $ "Reading migration graph " <> name <> " from " <> T.pack dir
181− liftIO $ readGraph dir name
182−
183−computeVertexHash :: MonadObelisk m => FilePath -> m Hash
184−computeVertexHash = getDirectoryHash [migrationDirName]
185−
186−-- | Verify the integrity of the migration graph in relation to the Git repo.
187−verifyMigration :: MonadObelisk m => FilePath -> m ()
188−verifyMigration obDir = do
189− upgradeGraph <- withSpinner "Reading migration graph" $
190− getMigrationGraph @Text obDir MigrationGraph_ObeliskUpgrade
191− withSpinner "Checking graph integrity" $
192− handleMigrationError $ ensureGraphIntegrity upgradeGraph
193− headVertex <- liftIO (doesDirectoryExist $ obDir </> ".git") >>= \case
194− True ->
195− withSpinner "Checking existence of HEAD vertex" $
196− getHeadVertex obDir
197− False -> do
198− hash <- computeVertexHash obDir
199− unless (hasVertex hash upgradeGraph) $
200− failWith $ "No vertex found for obelisk hash " <> hash
201− pure hash
202− withSpinner "Checking graph linearity" $
203− -- NOTE: We don't support merge commits (i.e., diamonds in a graph) yet.
204− -- Until we do, ensure that the graph is a fully connected linear list.
205− runExceptT (ensureGraphLinearity upgradeGraph) >>= \case
206− Left (NonLinearGraph_MultipleAdjacents vertex) ->
207− failWith $ "Graph is not linear; branches at vertex: " <> tshow vertex
208− Left (NonLinearGraph_NotConnected isolatedVertices) ->
209− failWith $ "Graph is partly linear, with isolated vertices: " <> tshow isolatedVertices
210− Left e ->
211− failWith $ "Error in migration graph: " <> tshow e
212− Right lastVertex -> unless (lastVertex == headVertex) $
213− failWith $ "Graph is linear, but its last vertex (" <> lastVertex <> ") is different from head vertex (" <> headVertex <> ")"
214−
215−-- | Create an edge from HEAD vertex to the hash corresponding to the Git
216−-- working copy. The HEAD vertex must already exist.
217−createMigrationEdgeFromHEAD :: MonadObelisk m => FilePath -> m ()
218−createMigrationEdgeFromHEAD obDir = do
219− headHash <- getHeadVertex obDir
220− wcHash <- getDirectoryHash migrationIgnore obDir
221− if (headHash == wcHash)
222− then
223− putLog Warning "No migration necessary (working copy has the same hash as that of HEAD)"
224− else do
225− writeEdge (migrationDir obDir) graphNames headHash wcHash >>= \case
226− Nothing ->
227− putLog Warning "No migration was created"
228− Just edgeDir ->
229− putLog Notice $ "Created edge: " <> T.pack edgeDir
230−
231−-- | Return the hash corresponding to HEAD
232−--
233−-- Fail if the hash does not exist in project's migration graph.
234−getHeadVertex :: MonadObelisk m => FilePath -> m Hash
235−getHeadVertex obDir = do
236− projectGraph <- getMigrationGraph @Text obDir MigrationGraph_ObeliskUpgrade
237− [headHash] <- getHashAtGitRevision ["HEAD"] migrationIgnore obDir
238− unless (hasVertex headHash projectGraph) $ do
239− -- This means that the HEAD commit has no vertex in the graph,
240− -- possibly due to developer negligence when commiting it.
241− -- Perhaps we should use a post-commit hook or some such thing
242− -- to reject such commits in the first place? For now, just
243− -- error out.
244− failWith $ "No vertex found for HEAD (" <> headHash <> ")"
245− return headHash
246−
247−-- | Create, or update, the migration graph with new edges and new vertices
248−-- corresponding to every commit in the Git history from HEAD.
249−--
250−-- NOTE: This creates a linear graph, and doesn't follow the Git graph
251−-- structure.
252−backfillGraph :: MonadObelisk m => Maybe Int -> FilePath -> m ()
253−backfillGraph lastN obDir = do
254− revs <- fmap (takeM lastN . fmap (fst . T.breakOn " ") . T.lines) $
255− readProc $ gitProc obDir ["log", "--pretty=oneline"]
256− -- Note: we need to take unique hashes only; this is fine for backfilling.
257− -- But future migrations should ensure that there are no duplicate hashes
258− -- (which would cause cycles) such as those introduced by revert commits.
259− vertices :: [Hash] <- withSpinnerNoTrail "Computing hash for git history" $
260− fmap (unique . reverse) $ getHashAtGitRevision revs [migrationDirName] obDir
261− void $ withSpinner'
262− ("Backfilling with " <> tshow (length vertices) <> " vertices")
263− (Just $ \n -> "Backfilled " <> tshow n <> " edges.") $ do
264− let vertexPairs = zip vertices $ drop 1 vertices
265− let edgesDir = migrationDir obDir
266− liftIO $ createDirectoryIfMissing False edgesDir
267− fmap (length . catMaybes) $ forM vertexPairs $ \(v1, v2) -> do
268− writeEdge edgesDir graphNames v1 v2
269− where
270− -- Return unique items in the list /while/ preserving order
271− unique = loop mempty
272− where
273− loop _ [] = []
274− loop s (x : xs)
275− | S.member x s = loop s xs
276− | otherwise = x : loop (S.insert x s) xs
277− takeM n' xs = case n' of
278− Just n -> take n xs
279− Nothing -> xs
280−
281−handleMigrationError :: MonadObelisk m => Except MigrationError a -> m a
282−handleMigrationError m = case runExcept m of
283− Left e -> failWith $ "Error in migration graph: " <> tshow e
284− Right a -> return a
285−
286−migrationDir :: FilePath -> FilePath
287−migrationDir project = project </> migrationDirName
288−
289−migrationIgnore :: [FilePath]
290−migrationIgnore = [migrationDirName]
291−
292−migrationDirName :: FilePath
293−migrationDirName = "migration"
lib/command/src/Obelisk/Command/Upgrade/Hash.hs+4−5
@@ -102,15 +102,14 @@ tidyUpGitWorkingCopy :: MonadObelisk m => FilePath -> m ()
102tidyUpGitWorkingCopy dir = withSpinnerNoTrail "Tidying up git working copy" $ do
102tidyUpGitWorkingCopy dir = withSpinnerNoTrail "Tidying up git working copy" $ do
103 ignored <- gitLsFiles dir ["--ignored", "--exclude-standard", "--others"]
103 ignored <- gitLsFiles dir ["--ignored", "--exclude-standard", "--others"]
104 untracked <- gitLsFiles dir ["--exclude-standard", "--others"]
104 untracked <- gitLsFiles dir ["--exclude-standard", "--others"]
105− putLog Debug $ T.pack $ "Ignored: " <> show (length ignored) <> " files."
105+ putLog Debug $ "Ignored: " <> T.pack (show $ length ignored) <> " files."
106− putLog Debug $ T.pack $ "Untracked files:\n" <> unlines untracked
106+ putLog Debug $ "Untracked files:\n" <> T.unlines untracked
107 withSpinnerNoTrail "Removing untracked and ignored files" $ do
107 withSpinnerNoTrail "Removing untracked and ignored files" $ do
108− forM_ (fmap (dir </>) $ ignored <> untracked) $
108+ forM_ (fmap ((dir </>) . T.unpack) $ ignored <> untracked) $
109 liftIO . removePathForcibly
109 liftIO . removePathForcibly
110 -- Empty directories won't be included in these lists. Git doesn't track them
110 -- Empty directories won't be included in these lists. Git doesn't track them
111 -- So we must delete these separately.
111 -- So we must delete these separately.
112 runProc $ proc "find" [dir, "-depth", "-empty", "-type", "d", "-delete"]
112 runProc $ proc "find" [dir, "-depth", "-empty", "-type", "d", "-delete"]
113 where
113 where
114− gitLsFiles pwd opts = fmap lines $ readProcessAndLogStderr Error $
114+ gitLsFiles pwd opts = fmap T.lines $ readProc $
115 (proc "git" $ ["ls-files", "."] <> opts) { cwd = Just pwd }
115 (proc "git" $ ["ls-files", "."] <> opts) { cwd = Just pwd }
116−
lib/command/src/Obelisk/Command/Utils.hs+104−6
@@ -1,16 +1,30 @@
1{-# LANGUAGE FlexibleContexts #-}
1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE LambdaCase #-}
3+{-# LANGUAGE MultiWayIf #-}
4+{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE OverloadedStrings #-}
5{-# LANGUAGE OverloadedStrings #-}
6+{-# LANGUAGE PatternGuards #-}
4module Obelisk.Command.Utils where
7module Obelisk.Command.Utils where
5
8
6−import Control.Applicative (liftA2)
9+import Control.Applicative hiding (many)
10+import Control.Monad.Except
7import Data.Bool (bool)
11import Data.Bool (bool)
12+import qualified Text.Megaparsec.Char.Lexer as ML
13+import Data.Bifunctor
14+import Data.Char
15+import Data.Either
8import Data.Semigroup ((<>))
16import Data.Semigroup ((<>))
17+import Data.Map (Map)
18+import qualified Data.Map as M
19+import Data.Maybe (maybeToList)
9import Data.Text (Text)
20import Data.Text (Text)
10import qualified Data.Text as T
21import qualified Data.Text as T
22+import Data.Void (Void)
11import System.Directory (canonicalizePath)
23import System.Directory (canonicalizePath)
12import System.Environment (getExecutablePath)
24import System.Environment (getExecutablePath)
13import qualified System.Process as P
25import qualified System.Process as P
26+import Text.Megaparsec as MP
27+import Text.Megaparsec.Char as MP
14
28
15import Obelisk.App (MonadObelisk)
29import Obelisk.App (MonadObelisk)
16import Obelisk.CliApp
30import Obelisk.CliApp
@@ -25,7 +39,7 @@ checkGitCleanStatus repo withIgnored = do
25 runGit = readProcessAndLogStderr Debug . gitProc repo
39 runGit = readProcessAndLogStderr Debug . gitProc repo
26 gitStatus = runGit $ ["status", "--porcelain"] <> bool [] ["--ignored"] withIgnored
40 gitStatus = runGit $ ["status", "--porcelain"] <> bool [] ["--ignored"] withIgnored
27 gitDiff = runGit ["diff"]
41 gitDiff = runGit ["diff"]
28− null <$> liftA2 (<>) gitStatus gitDiff
42+ T.null <$> liftA2 (<>) gitStatus gitDiff
29
43
30-- | Ensure that git repo is clean
44-- | Ensure that git repo is clean
31ensureCleanGitRepo :: MonadObelisk m => FilePath -> Bool -> Text -> m ()
45ensureCleanGitRepo :: MonadObelisk m => FilePath -> Bool -> Text -> m ()
@@ -46,9 +60,11 @@ initGit repo = do
46 git ["add", "."]
60 git ["add", "."]
47 git ["commit", "-m", "Initial commit."]
61 git ["commit", "-m", "Initial commit."]
48
62
63+gitProcNoRepo :: [String] -> P.CreateProcess
64+gitProcNoRepo = P.proc "git"
65+
49gitProc :: FilePath -> [String] -> P.CreateProcess
66gitProc :: FilePath -> [String] -> P.CreateProcess
50−gitProc repo argsRaw =
67+gitProc repo = gitProcNoRepo . runGitInDir
51− P.proc "git" $ runGitInDir argsRaw
52 where
68 where
53 runGitInDir args' = case filter (not . null) args' of
69 runGitInDir args' = case filter (not . null) args' of
54 args@("clone":_) -> args <> [repo]
70 args@("clone":_) -> args <> [repo]
@@ -60,7 +76,7 @@ copyDir src dest =
60 (P.proc "cp" ["-a", ".", dest]) { P.cwd = Just src }
76 (P.proc "cp" ["-a", ".", dest]) { P.cwd = Just src }
61
77
62readGitProcess :: MonadObelisk m => FilePath -> [String] -> m Text
78readGitProcess :: MonadObelisk m => FilePath -> [String] -> m Text
63−readGitProcess repo = fmap T.pack . readProcessAndLogStderr Notice . gitProc repo
79+readGitProcess repo = readProcessAndLogOutput (Debug, Notice) . gitProc repo
64
80
65processToShellString :: FilePath -> [String] -> String
81processToShellString :: FilePath -> [String] -> String
66processToShellString cmd args = unwords $ map quoteAndEscape (cmd : args)
82processToShellString cmd args = unwords $ map quoteAndEscape (cmd : args)
@@ -76,7 +92,89 @@ runProcSilently = callProcessAndLogOutput (Debug, Debug)
76
92
77-- | A simpler wrapper for CliApp's readProcessAndLogStderr with sensible defaults.
93-- | A simpler wrapper for CliApp's readProcessAndLogStderr with sensible defaults.
78readProc :: MonadObelisk m => P.CreateProcess -> m Text
94readProc :: MonadObelisk m => P.CreateProcess -> m Text
79−readProc = fmap T.pack . readProcessAndLogStderr Error
95+readProc = readProcessAndLogOutput (Debug, Error)
80
96
81tshow :: Show a => a -> Text
97tshow :: Show a => a -> Text
82tshow = T.pack . show
98tshow = T.pack . show
99+
100+gitLookupDefaultBranch :: GitLsRemoteMaps -> Either Text Text
101+gitLookupDefaultBranch (refs, _) = do
102+ ref <- case M.lookup GitRef_Head refs of
103+ Just ref -> pure ref
104+ Nothing -> throwError
105+ "No symref entry for HEAD. \
106+ \ Is your git version at least 1.8.5? \
107+ \ Otherwise `git ls-remote --symref` will not work."
108+ case ref of
109+ GitRef_Branch b -> pure b
110+ _ -> throwError $
111+ "Default ref " <> showGitRef ref <> " is not a branch!"
112+
113+gitLookupCommitForRef :: GitLsRemoteMaps -> GitRef -> Either Text CommitId
114+gitLookupCommitForRef (_, commits) ref = case M.lookup ref commits of
115+ Just a -> pure a
116+ Nothing -> throwError $ "Did not find commit for " <> showGitRef ref
117+
118+gitLsRemote
119+ :: MonadObelisk m
120+ => String
121+ -> Maybe GitRef
122+ -> m GitLsRemoteMaps
123+gitLsRemote repository mRef = do
124+ t <- readProc $ gitProcNoRepo $
125+ ["ls-remote", "--symref", repository]
126+ ++ (maybeToList $ T.unpack . showGitRef <$> mRef)
127+ maps <- case MP.runParser parseLsRemote "" t of
128+ Left err -> failWith $ T.pack $ MP.parseErrorPretty' t err
129+ Right table -> pure $ bimap M.fromList M.fromList $ partitionEithers $ table
130+ putLog Debug $ "git ls-remote maps: " <> T.pack (show maps)
131+ pure maps
132+
133+lexeme :: Parsec Void Text a -> Parsec Void Text a
134+lexeme = ML.lexeme $ void $ MP.takeWhileP (Just "within-line white space") $
135+ flip elem [' ', '\t']
136+
137+-- $ git ls-remote --symref git@github.com:obsidiansystems/obelisk.git HEAD
138+-- ref: refs/heads/master HEAD
139+-- d0a8d25dc93f0acd096bc4ff2f550da9e2d0c8f5 refs/heads/master
140+parseLsRemote :: Parsec Void Text [Either (GitRef, GitRef) (GitRef, CommitId)]
141+parseLsRemote =
142+ many ((fmap Left (try parseRef) <|> fmap Right parseCommit) <* try MP.eol) <* MP.eof
143+ where
144+ parseRef :: Parsec Void Text (GitRef, GitRef)
145+ parseRef = MP.label "ref and symbolic ref" $ do
146+ _ <- lexeme "ref:"
147+ ref <- lexeme $ MP.takeWhileP (Just "ref") $ not . isSpace
148+ symbolicRef <- lexeme $ MP.takeWhileP (Just "symbolic ref") $ not . isSpace
149+ return (toGitRef symbolicRef, toGitRef ref)
150+ parseCommit :: Parsec Void Text (GitRef, CommitId)
151+ parseCommit = MP.label "commit and ref" $ do
152+ commitId <- lexeme $ MP.takeWhileP (Just "commit id") $ not . isSpace
153+ ref <- lexeme $ MP.takeWhileP (Just "ref") $ not . isSpace
154+ return (toGitRef ref, commitId)
155+
156+data GitRef
157+ = GitRef_Head
158+ | GitRef_Branch Text
159+ | GitRef_Tag Text
160+ | GitRef_Other Text
161+ deriving (Show, Eq, Ord)
162+
163+showGitRef :: GitRef -> Text
164+showGitRef = \case
165+ GitRef_Head -> "HEAD"
166+ GitRef_Branch x -> "refs/heads/" <> x
167+ GitRef_Tag x -> "refs/tags/" <> x
168+ GitRef_Other x -> x
169+
170+toGitRef :: Text -> GitRef
171+toGitRef = \case
172+ "HEAD" -> GitRef_Head
173+ r -> if
174+ | Just s <- "refs/heads/" `T.stripPrefix` r -> GitRef_Branch s
175+ | Just s <- "refs/tags/" `T.stripPrefix` r -> GitRef_Tag s
176+ | otherwise -> GitRef_Other r
177+
178+type CommitId = Text
179+
180+type GitLsRemoteMaps = (Map GitRef GitRef, Map GitRef CommitId)
lib/command/src/Obelisk/Command/VmBuilder.hs+10−6
@@ -1,11 +1,12 @@
1{-# LANGUAGE FlexibleContexts #-}
1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE QuasiQuotes #-}
3{-# LANGUAGE QuasiQuotes #-}
4+{-# LANGUAGE ScopedTypeVariables #-}
4module Obelisk.Command.VmBuilder where
5module Obelisk.Command.VmBuilder where
5
6
6import Control.Applicative (liftA2)
7import Control.Applicative (liftA2)
7import Control.Monad (unless)
8import Control.Monad (unless)
8−import Control.Monad.Catch (try)
9+import Control.Monad.Catch (try, handle)
9import Control.Monad.IO.Class (liftIO)
10import Control.Monad.IO.Class (liftIO)
10import Data.Either (isRight)
11import Data.Either (isRight)
11import Data.Monoid ((<>))
12import Data.Monoid ((<>))
@@ -42,13 +43,16 @@ containerName = "obelisk-docker-nix-builder"
42
43
43-- | Check to see if the Docker container exists. This will exit with a helpful message if Docker is not installed.
44-- | Check to see if the Docker container exists. This will exit with a helpful message if Docker is not installed.
44containerExists :: MonadObelisk m => m Bool
45containerExists :: MonadObelisk m => m Bool
45−containerExists = withExitFailMessage needDockerMsg $ do
46+containerExists = handle (\(_ :: IOError) -> failWith needDockerMsg) $ do
46− containerNames <- fmap (map T.strip . T.lines . T.pack) $
47+ containerNames <- fmap (map T.strip . T.lines) $
47 readProcessAndLogStderr Error $
48 readProcessAndLogStderr Error $
48 proc "docker" ["container", "list", "--all", "--format", "{{.Names}}"]
49 proc "docker" ["container", "list", "--all", "--format", "{{.Names}}"]
49 pure $ containerName `elem` containerNames
50 pure $ containerName `elem` containerNames
50 where
51 where
52+ needDockerMsg = T.intercalate "\n"
51− needDockerMsg = "This feature requires that you have Docker installed and the `docker` command available on your PATH. Please go https://docs.docker.com/ to install Docker and try this command again."
53+ [ "This feature requires that you have Docker installed and the `docker` command available on your PATH."
54+ , "Please go https://docs.docker.com/ to install Docker and try this command again."
55+ ]
52
56
53-- | SSH port on localhost that connects to the container.
57-- | SSH port on localhost that connects to the container.
54containerSshPort :: Int
58containerSshPort :: Int
@@ -74,14 +78,14 @@ setupNixDocker stateDir = withSpinner ("Creating Docker container named " <> con
74 proc "ssh-keygen" ["-t", "ed25519", "-f", stateDir </> sshKeyFileName, "-P", ""]
78 proc "ssh-keygen" ["-t", "ed25519", "-f", stateDir </> sshKeyFileName, "-P", ""]
75
79
76 -- Build the docker container (which uses the SSH keys in the 'ssh' folder)
80 -- Build the docker container (which uses the SSH keys in the 'ssh' folder)
77− containerId <- readProcessAndLogStderr Error $
81+ containerId <- fmap T.strip $ readProcessAndLogStderr Error $
78 proc "docker" ["build", stateDir, "--quiet"]
82 proc "docker" ["build", stateDir, "--quiet"]
79 callProcessAndLogOutput (Debug, Error) $ proc "docker"
83 callProcessAndLogOutput (Debug, Error) $ proc "docker"
80 [ "run"
84 [ "run"
81 , "--restart", "always"
85 , "--restart", "always"
82 , "--detach"
86 , "--detach"
83 , "--publish", show containerSshPort <> ":22"
87 , "--publish", show containerSshPort <> ":22"
84− , "--name", containerName, containerId
88+ , "--name", T.unpack containerName, T.unpack containerId
85 ]
89 ]
86 exists <- containerExists
90 exists <- containerExists
87 unless exists $
91 unless exists $
lib/migration/obelisk-migration.cabaldeleted−24
@@ -1,24 +0,0 @@
1−name: obelisk-migration
2−version: 0.1
3−license: BSD3
4−build-type: Simple
5−cabal-version: >=1.2
6−
7−library
8− hs-source-dirs: src
9− build-depends:
10− algebraic-graphs >= 0.2
11− , base
12− , containers
13− , directory
14− , exceptions
15− , filepath
16− , mtl
17− , obelisk-cliapp
18− , process
19− , text
20− , transformers
21− exposed-modules:
22− Obelisk.Migration
23− other-modules:
24− ghc-options: -Wall -fobject-code
lib/migration/src/Obelisk/Migration.hsdeleted−223
@@ -1,223 +0,0 @@
1−{-# LANGUAGE FlexibleContexts #-}
2−{-# LANGUAGE LambdaCase #-}
3−{-# LANGUAGE OverloadedStrings #-}
4−{-# LANGUAGE ScopedTypeVariables #-}
5−{-# LANGUAGE TupleSections #-}
6−module Obelisk.Migration where
7−
8−import Control.Monad (forM, forM_, unless, void)
9−import Control.Monad.Except
10−import Control.Monad.IO.Class (MonadIO, liftIO)
11−import Control.Monad.State.Strict (evalStateT, get, put)
12−import Data.Map (Map)
13−import qualified Data.Map as Map
14−import Data.Maybe (catMaybes)
15−import Data.Semigroup ((<>))
16−import Data.Set (Set)
17−import qualified Data.Set as Set
18−import Data.Text (Text)
19−import qualified Data.Text as T
20−import qualified Data.Text.IO as T
21−import System.Directory
22−import System.FilePath
23−
24−import Algebra.Graph.AdjacencyMap
25−
26−type Hash = Text
27−
28−-- Migration graph with edge metadata
29−data Migration action = Migration
30− { _migration_graph :: AdjacencyMap Hash
31− , _migration_actions :: Map (Hash, Hash) action -- Edge metadata
32− }
33− deriving (Eq, Show)
34−
35−-- A path is a list of edges
36−type Path = [(Hash, Hash)]
37−
38−data MigrationError
39− = GraphInternalError Text
40− | CyclicGraphError
41− | MultipleTerminalVertices
42− | NoTerminalVertex
43− | NonEquivalentPaths Hash Hash
44− | MissingEdgeInActionMap (Hash, Hash)
45− | NonLinearGraph_MultipleAdjacents Hash
46− | NonLinearGraph_NotConnected (Set Hash)
47− deriving (Eq, Ord, Show)
48−
49−class Action action where
50− parseEdgeMeta :: Text -> action
51−
52−instance Action Text where
53− parseEdgeMeta = id
54−
55−-- | Get the directed-acylic graph of migration
56−-- TODO: Consider calling getDag only when reading the graph for efficiency.
57−getDag :: (MonadError MigrationError m, Ord a) => AdjacencyMap a -> m (AdjacencyMap a)
58−getDag g = case topSort g of
59− Just _ -> pure g
60− Nothing -> throwError CyclicGraphError
61−
62−-- | Read the graph from a directory of files.
63−readGraph :: Action action => FilePath -> Text -> IO (Maybe (Migration action))
64−readGraph root name = doesDirectoryExist root >>= \case
65− False -> return Nothing
66− True -> do
67− allVertexPairs <- listDirectory root >>= return . catMaybes . fmap getEdgeVertices
68− edgesInfo <- fmap catMaybes $ forM allVertexPairs $ \vs -> do
69− getEdgeFor name vs >>= return . fmap (vs, )
70− return $ pure $ Migration (edges $ fmap fst edgesInfo) (Map.fromList edgesInfo)
71− where
72− getEdgeVertices p = case T.splitOn "-" $ T.pack p of
73− [v1, v2] -> Just (v1, v2)
74− _ -> Nothing
75− getEdgeFor graph (v1, v2) = do
76− let f = root </> (T.unpack $ v1 <> "-" <> v2) </> T.unpack graph
77− doesFileExist f >>= \case
78− True -> do
79− c <- parseEdgeMeta <$> T.readFile f
80− return $ Just c
81− False -> do
82− return Nothing
83−
84−-- | Ensure that the migration graph is correct
85−--
86−-- In a correct migration graph: for all pairs of nodes, all paths between
87−-- those nodes have the same migration value
88−--
89−-- Throw the following if integrity check fails
90−-- * `CyclicGraphError`
91−-- * `NonEquivalentPaths`
92−--
93−-- Complexity: O(V+E)
94−ensureGraphIntegrity
95− :: (MonadError MigrationError m, Monoid action, Ord action)
96− => Migration action -> m ()
97−ensureGraphIntegrity m = do
98− graph <- fmap adjacencyMap $ getDag $ _migration_graph m
99− firstVertex <- getFirst $ _migration_graph m
100− let
101− visitFrom visited acc start = case Map.lookup start graph of
102− Nothing -> pure ()
103− Just adjs -> void $ flip traverse (Set.toList adjs) $ \adj -> do
104− acc' <- fmap (mappend acc) $ getAction m (start, adj)
105− visited' <- case Map.lookup adj visited of
106− Nothing -> pure $ Map.insert adj acc' visited
107− Just adjAcc -> if acc' == adjAcc
108− then pure visited
109− else throwError $ NonEquivalentPaths start adj
110− visitFrom visited' acc' adj
111− -- We only check all paths from the _first_ vertex; it is not necessary to
112− -- check all paths between _all_ pairs of vertices as that can be proved by
113− -- induction, as long as there is exactly one first vertex (which we check on
114− -- further above).
115− visitFrom mempty mempty firstVertex
116−
117−-- | Ensure that the graph is a fully connected linear list
118−--
119−-- Returns the last vertex in the linear list.
120−ensureGraphLinearity :: MonadError MigrationError m => Migration action -> m Hash
121−ensureGraphLinearity m = do
122− graph <- fmap adjacencyMap $ getDag $ _migration_graph m
123− firstVertex <- getFirst $ _migration_graph m
124− let
125− allVertices = vertexSet $ _migration_graph m
126− visitFrom start = case Map.lookup start graph of
127− Nothing -> throwError $ GraphInternalError $ "Vertex not found: " <> start
128− Just adjs -> case (Set.toList adjs) of
129− [] -> pure (start, [start])
130− [adj] -> fmap (start :) <$> visitFrom adj
131− _ -> throwError $ NonLinearGraph_MultipleAdjacents start
132− (lastVertex, visitedVertices) <- visitFrom firstVertex
133− let unvisitedVertices = Set.difference allVertices $ Set.fromList visitedVertices
134− if Set.null unvisitedVertices
135− then pure lastVertex
136− else throwError $ NonLinearGraph_NotConnected unvisitedVertices
137−
138−-- | Find the concatenated actions between two vertices
139−--
140−-- All paths between the vertices must have the same mappend'ed action;
141−-- otherwise this will throw.
142−--
143−-- Complexity: O(V+E)
144−findPathAction
145− :: (MonadError MigrationError m, Action action, Monoid action, Ord action)
146− => Migration action -> Hash -> Hash -> m (Maybe action)
147−findPathAction m start end = flip evalStateT Map.empty $ do
148− graph <- fmap adjacencyMap $ getDag $ _migration_graph m
149− let
150− findPathFromCached start' = do
151− -- TODO: refactor the caching part into a separate `memoize` function
152− cache <- get
153− case Map.lookup start' cache of
154− Just result ->
155− pure result
156− Nothing -> do
157− result <- findPathFrom start'
158− put $ Map.insert start' result cache
159− pure result
160− findPathFrom start' = if start' == end
161− then
162− pure $ Just mempty
163− else case Map.lookup start' graph of
164− Just adjs -> do
165− actions <- fmap catMaybes $ flip traverse (Set.toList adjs) $ \adj -> do
166− action0 <- getAction m (start', adj)
167− actionM <- findPathFromCached adj
168− pure $ fmap (mappend action0) $ actionM
169− case uniqs actions of
170− [] -> pure Nothing
171− [v] -> pure $ Just v -- Exactly one monoidal value; accept.
172− _ -> throwError $ NonEquivalentPaths start' end
173− Nothing ->
174− pure Nothing
175− uniqs = Set.toList . Set.fromList
176− findPathFromCached start
177−
178−hasVertex :: Hash -> Migration action -> Bool
179−hasVertex h (Migration g _) = Set.member h $ vertexSet g
180−
181−-- | Get the action for the given edge (which must exist)
182−getAction :: MonadError MigrationError m => Migration action -> (Hash, Hash) -> m action
183−getAction (Migration _ h) e = case Map.lookup e h of
184− Just v -> pure v
185− Nothing -> throwError $ MissingEdgeInActionMap e
186−
187−-- | Get the last vertex of the given DAG. Nothing if empty graph.
188−--
189−-- Assumes that the graph is fully connected.
190−getLast :: (MonadError MigrationError m, Ord a, Eq a) => AdjacencyMap a -> m a
191−getLast g = lastVertices >>= \case
192− [] -> throwError NoTerminalVertex
193− [x] -> pure x
194− _ -> throwError MultipleTerminalVertices
195− where
196− lastVertices
197− = pure
198− . fmap fst
199− . filter (\(_, nexts) -> nexts == [])
200− . adjacencyList
201− =<< getDag g
202−
203−-- | Get the first vertex of the given DAG. Nothing if empty graph.
204−getFirst :: (MonadError MigrationError m, Ord a, Eq a) => AdjacencyMap a -> m a
205−getFirst = getLast . transpose
206−
207−-- | Write an edge directly to the filesystem.
208−--
209−-- Actions are written with empty string.
210−--
211−-- Return the edge directory created.
212−writeEdge :: MonadIO m => FilePath -> [Text] -> Hash -> Hash -> m (Maybe FilePath)
213−writeEdge dir actionFiles v1 v2 = do
214− unless (v1 /= v2) $
215− fail $ "Cannot create self loop with: " <> T.unpack v1
216− let edgeDir = dir </> (T.unpack $ v1 <> "-" <> v2)
217− liftIO (doesDirectoryExist edgeDir) >>= \case
218− True -> pure Nothing
219− False -> do
220− liftIO $ createDirectory edgeDir
221− forM_ actionFiles $ \fp -> liftIO $
222− writeFile (edgeDir </> T.unpack fp) ""
223− pure $ Just edgeDir
lib/selftest/src/Obelisk/SelfTest.hs+16−18
@@ -1,3 +1,4 @@
1+{-# LANGUAGE EmptyCase #-}
1{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE LambdaCase #-}
2{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE OverloadedStrings #-}
3{-# LANGUAGE PatternGuards #-}
4{-# LANGUAGE PatternGuards #-}
@@ -14,6 +15,7 @@ import Data.Semigroup (Semigroup, (<>))
14import qualified Data.Set as Set
15import qualified Data.Set as Set
15import Data.String
16import Data.String
16import Data.Text (Text)
17import Data.Text (Text)
18+import Data.Void
17import qualified Data.Text as T
19import qualified Data.Text as T
18import qualified Data.Text.IO as T
20import qualified Data.Text.IO as T
19import qualified Network.HTTP.Client as HTTP
21import qualified Network.HTTP.Client as HTTP
@@ -27,7 +29,6 @@ import System.Info
27import System.IO (Handle, hClose)
29import System.IO (Handle, hClose)
28import System.IO.Temp
30import System.IO.Temp
29import System.Process (readProcessWithExitCode, CreateProcess(cwd), readCreateProcessWithExitCode, proc)
31import System.Process (readProcessWithExitCode, CreateProcess(cwd), readCreateProcessWithExitCode, proc)
30−import System.Timeout
31import Test.Hspec
32import Test.Hspec
32import Test.HUnit.Base
33import Test.HUnit.Base
33
34
@@ -38,7 +39,7 @@ import Obelisk.Run (getConfigRoute)
38data ObRunState
39data ObRunState
39 = ObRunState_Init
40 = ObRunState_Init
40 | ObRunState_Startup
41 | ObRunState_Startup
41− | ObRunState_BackendStarted Text -- Port of backend
42+ | ObRunState_BackendStarted
42 deriving (Eq, Show)
43 deriving (Eq, Show)
43
44
44doubleQuotes :: (IsString a, Semigroup a) => a -> a
45doubleQuotes :: (IsString a, Semigroup a) => a -> a
@@ -53,9 +54,10 @@ commit msg = void $ run "git"
53 , doubleQuotes msg
54 , doubleQuotes msg
54 ]
55 ]
55
56
57+-- TODO replace Void and stop using loosely typed synchronous exceptions
56−runCli :: MonadIO m => CliT IO a -> m a
58+runCli :: MonadIO m => CliT Void IO a -> m a
57runCli f = liftIO $ do
59runCli f = liftIO $ do
58− c <- newCliConfig Notice False False
60+ c <- newCliConfig Notice False False (\case {})
59 CliApp.runCli c f
61 CliApp.runCli c f
60
62
61tshow :: Show a => a -> Text
63tshow :: Show a => a -> Text
@@ -220,12 +222,12 @@ testObRunInDir mdir httpManager = handle_sh (\case ExitSuccess -> pure (); e ->
220 writefile "config/common/route" . uri =<< liftIO getFreePort -- Use a free port initially
222 writefile "config/common/route" . uri =<< liftIO getFreePort -- Use a free port initially
221 maybe id chdir mdir $ runHandle "ob" ["run"] $ \stdout -> do
223 maybe id chdir mdir $ runHandle "ob" ["run"] $ \stdout -> do
222 freePort <- liftIO getFreePort
224 freePort <- liftIO getFreePort
223− (_, firstUri) <- handleObRunStdout httpManager stdout
225+ firstUri <- handleObRunStdout httpManager stdout
224 let newUri = uri freePort
226 let newUri = uri freePort
225 when (firstUri == newUri) $ errorExit $
227 when (firstUri == newUri) $ errorExit $
226 "Startup URI (" <> firstUri <> ") is the same as test URI (" <> newUri <> ")"
228 "Startup URI (" <> firstUri <> ") is the same as test URI (" <> newUri <> ")"
227 maybe id (\_ -> chdir "..") mdir $ alterRouteTo newUri stdout
229 maybe id (\_ -> chdir "..") mdir $ alterRouteTo newUri stdout
228− (_, runningUri) <- handleObRunStdout httpManager stdout
230+ runningUri <- handleObRunStdout httpManager stdout
229 if runningUri /= newUri
231 if runningUri /= newUri
230 then errorExit $ "Reloading failed: expected " <> newUri <> " but got " <> runningUri
232 then errorExit $ "Reloading failed: expected " <> newUri <> " but got " <> runningUri
231 else exit 0
233 else exit 0
@@ -272,32 +274,28 @@ alterRouteTo uri stdout = do
272 "Reloading failed: " <> T.pack (show t)
274 "Reloading failed: " <> T.pack (show t)
273
275
274-- | Handle stdout of `ob run`: check that the frontend and backend servers are started correctly
276-- | Handle stdout of `ob run`: check that the frontend and backend servers are started correctly
275−handleObRunStdout :: HTTP.Manager -> Handle -> Sh (Text, Text)
277+handleObRunStdout :: HTTP.Manager -> Handle -> Sh Text
276handleObRunStdout httpManager stdout = flip fix ObRunState_Init $ \loop state -> do
278handleObRunStdout httpManager stdout = flip fix ObRunState_Init $ \loop state -> do
277 liftIO (T.hGetLine stdout) >>= \t -> case state of
279 liftIO (T.hGetLine stdout) >>= \t -> case state of
278 ObRunState_Init
280 ObRunState_Init
279− | "Running test..." `T.isPrefixOf` t -> loop ObRunState_Startup
281+ | "Running test..." `T.isPrefixOf` t -> loop ObRunState_BackendStarted
280 ObRunState_Startup
282 ObRunState_Startup
281 | t == "backend stopped; make a change to your code to reload" -> loop ObRunState_Startup
283 | t == "backend stopped; make a change to your code to reload" -> loop ObRunState_Startup
282− | Just port <- "Backend running on port " `T.stripPrefix` t -> loop $ ObRunState_BackendStarted port
284+ -- | Just port <- "Backend running on port " `T.stripPrefix` t -> loop $ ObRunState_BackendStarted port
283 | not (T.null t) -> errorExit $ "Startup: " <> t -- If theres any other output here, startup failed
285 | not (T.null t) -> errorExit $ "Startup: " <> t -- If theres any other output here, startup failed
284− ObRunState_BackendStarted port
286+ ObRunState_BackendStarted
285 | Just uri <- "Frontend running on " `T.stripPrefix` t -> do
287 | Just uri <- "Frontend running on " `T.stripPrefix` t -> do
286− obRunCheck httpManager stdout port uri
288+ obRunCheck httpManager stdout uri
287− pure (port, uri)
289+ pure uri
288 | not (T.null t) -> errorExit $ "Started: " <> t -- If theres any other output here, startup failed
290 | not (T.null t) -> errorExit $ "Started: " <> t -- If theres any other output here, startup failed
289 _ -> loop state
291 _ -> loop state
290
292
291-- | Make requests to frontend/backend servers to check they are working properly
293-- | Make requests to frontend/backend servers to check they are working properly
292−obRunCheck :: HTTP.Manager -> Handle -> Text -> Text -> Sh ()
294+obRunCheck :: HTTP.Manager -> Handle -> Text -> Sh ()
293−obRunCheck httpManager stdout backendPort frontendUri = do
295+obRunCheck httpManager _stdout frontendUri = do
294 let req uri = liftIO $ HTTP.parseRequest (T.unpack uri) >>= flip HTTP.httpLbs httpManager
296 let req uri = liftIO $ HTTP.parseRequest (T.unpack uri) >>= flip HTTP.httpLbs httpManager
295 req frontendUri >>= \r -> when (HTTP.responseStatus r /= HTTP.ok200) $ errorExit $
297 req frontendUri >>= \r -> when (HTTP.responseStatus r /= HTTP.ok200) $ errorExit $
296 "Request to frontend server failed: " <> T.pack (show r)
298 "Request to frontend server failed: " <> T.pack (show r)
297− void $ req $ "http://localhost:" <> backendPort
298− liftIO (timeout 1000000 $ T.hGetLine stdout) >>= \case
299− Just t | "127.0.0.1" `T.isPrefixOf` t -> pure () -- Backend request logged
300− x -> errorExit $ "Couldn't get backend request log: " <> T.pack (show x)
301
299
302getFreePort :: IO Socket.PortNumber
300getFreePort :: IO Socket.PortNumber
303getFreePort = Socket.withSocketsDo $ do
301getFreePort = Socket.withSocketsDo $ do
migration/001efbbe866b66eebc6ee1ea0a906f2d-b0c1d039514a686529561f186332c91e/obelisk-handoffdeleted

No changes to the content.

migration/001efbbe866b66eebc6ee1ea0a906f2d-b0c1d039514a686529561f186332c91e/obelisk-upgradedeleted

No changes to the content.

migration/00a480749e96ef7e21fbe8f4943152b1-abdb013baf130e1bd7e7fd04e535c44c/obelisk-handoffdeleted

No changes to the content.

migration/00a480749e96ef7e21fbe8f4943152b1-abdb013baf130e1bd7e7fd04e535c44c/obelisk-upgradedeleted

No changes to the content.

migration/00bee4377690b5040bd5b3702dce2a88-98629a336dcd5fa3524a09f8ea6ad636/obelisk-handoffdeleted

No changes to the content.

migration/00bee4377690b5040bd5b3702dce2a88-98629a336dcd5fa3524a09f8ea6ad636/obelisk-upgradedeleted

No changes to the content.

migration/00c627540326314c7154cc209e8a71e9-67bfa5b784a35e66875fb74ad84a38c0/obelisk-handoffdeleted

No changes to the content.

migration/00c627540326314c7154cc209e8a71e9-67bfa5b784a35e66875fb74ad84a38c0/obelisk-upgradedeleted

No changes to the content.

migration/01c0ee6c93a3f9f69e097c41169927ac-2913c440c7ad7731aae96e60a86bf7a8/obelisk-handoffdeleted

No changes to the content.

migration/01c0ee6c93a3f9f69e097c41169927ac-2913c440c7ad7731aae96e60a86bf7a8/obelisk-upgradedeleted

No changes to the content.

migration/01ddc6354698efa1ae5822da3be562dc-a536d01b9c489f5e00e30abf27427da0/obelisk-handoffdeleted

No changes to the content.

migration/01ddc6354698efa1ae5822da3be562dc-a536d01b9c489f5e00e30abf27427da0/obelisk-upgradedeleted

No changes to the content.

migration/01fb7610e4184ad1b491267fcb0c7f43-c0c1452986b8d4c181bb0c6c83c56a2f/obelisk-handoffdeleted

No changes to the content.

migration/01fb7610e4184ad1b491267fcb0c7f43-c0c1452986b8d4c181bb0c6c83c56a2f/obelisk-upgradedeleted

No changes to the content.

migration/0298e61f6a03e553df08dcef03e27bd1-06d184d1fb27966294a8fee1c7df7cb6/obelisk-handoffdeleted

No changes to the content.

migration/0298e61f6a03e553df08dcef03e27bd1-06d184d1fb27966294a8fee1c7df7cb6/obelisk-upgradedeleted

No changes to the content.

migration/02d0f8b5c7472e6f8a99ec2cfcb59807-5b6770965bbef440db49b0703cd243a3/obelisk-handoffdeleted

No changes to the content.

migration/02d0f8b5c7472e6f8a99ec2cfcb59807-5b6770965bbef440db49b0703cd243a3/obelisk-upgradedeleted

No changes to the content.

migration/02f532fd8bb64a167a5349c2ba8e3331-1088e2464720e12067dd74683546b132/obelisk-handoffdeleted

No changes to the content.

migration/02f532fd8bb64a167a5349c2ba8e3331-1088e2464720e12067dd74683546b132/obelisk-upgradedeleted

No changes to the content.

migration/02fb88dab35884e09deef1721c1cfc13-ae824b83b569b3b23b8e198190371ca0/obelisk-handoffdeleted

No changes to the content.

migration/02fb88dab35884e09deef1721c1cfc13-ae824b83b569b3b23b8e198190371ca0/obelisk-upgradedeleted

No changes to the content.

migration/030ed18dacf3571cbb9e3e7d9d99627b-d37d70fe5d7d11e68b59ce12022281c9/obelisk-handoffdeleted

No changes to the content.

migration/030ed18dacf3571cbb9e3e7d9d99627b-d37d70fe5d7d11e68b59ce12022281c9/obelisk-upgradedeleted

No changes to the content.

migration/03b845f308e73a1567eb843dfca182d2-e9ec84bfe7099b713c0fda32308f5815/obelisk-handoffdeleted

No changes to the content.

migration/03b845f308e73a1567eb843dfca182d2-e9ec84bfe7099b713c0fda32308f5815/obelisk-upgradedeleted

No changes to the content.

migration/03b9747848d7f3e995b118f776ef96c7-3da702ef7f531ad6db874ac3f85e9c06/obelisk-handoffdeleted−1
@@ -1 +0,0 @@
1−True
migration/03b9747848d7f3e995b118f776ef96c7-3da702ef7f531ad6db874ac3f85e9c06/obelisk-upgradedeleted

No changes to the content.

migration/04a5ae41e8fcef5f719cb84d01430382-f391c6a74ee14217ce4565c278fceed6/obelisk-handoffdeleted

No changes to the content.

migration/04a5ae41e8fcef5f719cb84d01430382-f391c6a74ee14217ce4565c278fceed6/obelisk-upgradedeleted

No changes to the content.

migration/04dd95ecb889ac1b0a616ddfeec781c4-f790ac9400501511b4ee045e22bc5fe1/obelisk-handoffdeleted

No changes to the content.

migration/04dd95ecb889ac1b0a616ddfeec781c4-f790ac9400501511b4ee045e22bc5fe1/obelisk-upgradedeleted

No changes to the content.

migration/0535e06dd0d61f3e6970b491a17cf1f8-28a6ada033c86e5ae914cc31cecb6239/obelisk-handoffdeleted

No changes to the content.

migration/0535e06dd0d61f3e6970b491a17cf1f8-28a6ada033c86e5ae914cc31cecb6239/obelisk-upgradedeleted

No changes to the content.

migration/053c0b2f84a7a2eadeb5c3f9575ffa0d-2600ab2ec96d3177d2a6b3462e09862d/obelisk-handoffdeleted

No changes to the content.

migration/053c0b2f84a7a2eadeb5c3f9575ffa0d-2600ab2ec96d3177d2a6b3462e09862d/obelisk-upgradedeleted

No changes to the content.

migration/063665b78b6705e7de952f73fa9797bf-172e629829334d2b33cda8d3b5e0b148/obelisk-handoffdeleted

No changes to the content.

migration/063665b78b6705e7de952f73fa9797bf-172e629829334d2b33cda8d3b5e0b148/obelisk-upgradedeleted

No changes to the content.

migration/06d184d1fb27966294a8fee1c7df7cb6-b1692927da5ed59af72fac5be8094fa2/obelisk-handoffdeleted

No changes to the content.

migration/06d184d1fb27966294a8fee1c7df7cb6-b1692927da5ed59af72fac5be8094fa2/obelisk-upgradedeleted

No changes to the content.

migration/071f5b3326b8886de3eddc927b80eb10-28e25b7a8812869a709579cd34e7bcb4/obelisk-handoffdeleted

No changes to the content.

migration/071f5b3326b8886de3eddc927b80eb10-28e25b7a8812869a709579cd34e7bcb4/obelisk-upgradedeleted

No changes to the content.

migration/07900e6c41ab9a78917f66fcf7e0d9b8-554c459ff2cced3e1b11241ed403890d/obelisk-handoffdeleted

No changes to the content.

migration/07900e6c41ab9a78917f66fcf7e0d9b8-554c459ff2cced3e1b11241ed403890d/obelisk-upgradedeleted

No changes to the content.

migration/07900e6c41ab9a78917f66fcf7e0d9b8-8c84f81d9b09a5e0f028f3c6341ffb36/obelisk-handoffdeleted

No changes to the content.

migration/07900e6c41ab9a78917f66fcf7e0d9b8-8c84f81d9b09a5e0f028f3c6341ffb36/obelisk-upgradedeleted−15
@@ -1,15 +0,0 @@
1−# ob deploy: HTTPs support
2−
3−Obelisk deployments now support HTTPs. You must upgrade the deployment repo
4−associated with the obelisk project as follows:
5−
6−```
7−cd /your/project's/deployment/repo
8−echo True > enable_https
9−echo admin@yoursite.com > admin_email
10−echo https://yoursite.com/ > config/common/route
11−git add ... && git commit ...
12−ob deploy push
13−```
14−
15−If you do not wish to enable HTTPs, write `False` to `enable_https` instead.
migration/0804ef73b54a4dc7fbde18147f33b4f9-00bee4377690b5040bd5b3702dce2a88/obelisk-handoffdeleted

No changes to the content.

migration/0804ef73b54a4dc7fbde18147f33b4f9-00bee4377690b5040bd5b3702dce2a88/obelisk-upgradedeleted

No changes to the content.

migration/08dbdf23867a8efa680283ad251d3429-f2a9ba4a93c3a04acbee2211bca9e27a/obelisk-handoffdeleted

No changes to the content.

migration/08dbdf23867a8efa680283ad251d3429-f2a9ba4a93c3a04acbee2211bca9e27a/obelisk-upgradedeleted

No changes to the content.

migration/0abd9d31c77be8c9a9e83bf1f73276f6-fc42c5fc24031fc6a8836a10cfb45143/obelisk-handoffdeleted

No changes to the content.

migration/0abd9d31c77be8c9a9e83bf1f73276f6-fc42c5fc24031fc6a8836a10cfb45143/obelisk-upgradedeleted

No changes to the content.

migration/0b2cab546a1526414096980fca85d0d3-99aebbfcac51725464bc59571b7d71b8/obelisk-handoffdeleted

No changes to the content.

migration/0b2cab546a1526414096980fca85d0d3-99aebbfcac51725464bc59571b7d71b8/obelisk-upgradedeleted

No changes to the content.

migration/0c6127453069ad707e34ddfedb67e2f9-7c98ef4a123c1a580d368d14e54961b7/obelisk-handoffdeleted

No changes to the content.

migration/0c6127453069ad707e34ddfedb67e2f9-7c98ef4a123c1a580d368d14e54961b7/obelisk-upgradedeleted

No changes to the content.

migration/0c9826e42d5d4fa9988c7db53722826e-c56de2f95c90def16704f62639246bbc/obelisk-handoffdeleted

No changes to the content.

migration/0c9826e42d5d4fa9988c7db53722826e-c56de2f95c90def16704f62639246bbc/obelisk-upgradedeleted

No changes to the content.

migration/0c991bc3c06801f72df48486ee78e350-58479e482d3828ce44f2c8371ed9135a/obelisk-handoffdeleted

No changes to the content.

migration/0c991bc3c06801f72df48486ee78e350-58479e482d3828ce44f2c8371ed9135a/obelisk-upgradedeleted

No changes to the content.

migration/0d3b4cfe9b4c72b830780a4c44942176-214979923f2d7e6278856493c1978fdc/obelisk-handoffdeleted

No changes to the content.

migration/0d3b4cfe9b4c72b830780a4c44942176-214979923f2d7e6278856493c1978fdc/obelisk-upgradedeleted

No changes to the content.

migration/0da1150f0e9fe57d1fafbb6cabe24fa1-a632452cf9c5956becd1a40512472b43/obelisk-handoffdeleted

No changes to the content.

migration/0da1150f0e9fe57d1fafbb6cabe24fa1-a632452cf9c5956becd1a40512472b43/obelisk-upgradedeleted

No changes to the content.

migration/0e4d0f0f0af0925474b0d772be2b145f-b82e9c3fe22feff4bb3a6be49943fd6c/obelisk-handoffdeleted

No changes to the content.

migration/0e4d0f0f0af0925474b0d772be2b145f-b82e9c3fe22feff4bb3a6be49943fd6c/obelisk-upgradedeleted

No changes to the content.

migration/0ec6f67d94d3913cf3243d813238ec39-0804ef73b54a4dc7fbde18147f33b4f9/obelisk-handoffdeleted

No changes to the content.

migration/0ec6f67d94d3913cf3243d813238ec39-0804ef73b54a4dc7fbde18147f33b4f9/obelisk-upgradedeleted

No changes to the content.

migration/0f78d9d6875933336bbf0c1c8888b73f-d1b3f5f5375558bf91d55c88547784b9/obelisk-handoffdeleted

No changes to the content.

migration/0f78d9d6875933336bbf0c1c8888b73f-d1b3f5f5375558bf91d55c88547784b9/obelisk-upgradedeleted

No changes to the content.

migration/0fb3a912a8aaf5ef6f734a25f0bce7e2-cccf4140dc336263489bcf67c8c58f86/obelisk-handoffdeleted

No changes to the content.

migration/0fb3a912a8aaf5ef6f734a25f0bce7e2-cccf4140dc336263489bcf67c8c58f86/obelisk-upgradedeleted

No changes to the content.

migration/0fba399e046852d4ecf8e1dad831a2f9-6620e6dc5622593e5f671127af9ade05/obelisk-handoffdeleted

No changes to the content.

migration/0fba399e046852d4ecf8e1dad831a2f9-6620e6dc5622593e5f671127af9ade05/obelisk-upgradedeleted

No changes to the content.

migration/0fe60df438daa8a2cca5f2b569e361a5-2e3e85cc59aa31f24f18c027542c0510/obelisk-handoffdeleted

No changes to the content.

migration/0fe60df438daa8a2cca5f2b569e361a5-2e3e85cc59aa31f24f18c027542c0510/obelisk-upgradedeleted

No changes to the content.

migration/1088e2464720e12067dd74683546b132-b2282679f6f63cec89d921c3dd512d1e/obelisk-handoffdeleted

No changes to the content.

migration/1088e2464720e12067dd74683546b132-b2282679f6f63cec89d921c3dd512d1e/obelisk-upgradedeleted

No changes to the content.

migration/11a5917ea91e021f1fa541a2fe158c80-d8adb57b2f2266e128ebb6f6d7e65920/obelisk-handoffdeleted

No changes to the content.

migration/11a5917ea91e021f1fa541a2fe158c80-d8adb57b2f2266e128ebb6f6d7e65920/obelisk-upgradedeleted

No changes to the content.

migration/11f38b38c2d38004bb8a9dbfe2ef3e4a-29d9b8b8ae9698888f3ea90b10ff5e92/obelisk-handoffdeleted

No changes to the content.

migration/11f38b38c2d38004bb8a9dbfe2ef3e4a-29d9b8b8ae9698888f3ea90b10ff5e92/obelisk-upgradedeleted

No changes to the content.

migration/1269155fffe21926f3704d5077e04332-1a97559d049bf85cebb762b7e7b70db1/obelisk-handoffdeleted

No changes to the content.

migration/1269155fffe21926f3704d5077e04332-1a97559d049bf85cebb762b7e7b70db1/obelisk-upgradedeleted

No changes to the content.

migration/12c8a24c34c2d8441f3181d179c2baab-bd6728737dffcc3505d30ada344e2f4b/obelisk-handoffdeleted

No changes to the content.

migration/12c8a24c34c2d8441f3181d179c2baab-bd6728737dffcc3505d30ada344e2f4b/obelisk-upgradedeleted

No changes to the content.

migration/131e1d5cc8163ce9a174a8782be23fe7-e323ce1352e512109f1609276fb509b4/obelisk-handoffdeleted

No changes to the content.

migration/131e1d5cc8163ce9a174a8782be23fe7-e323ce1352e512109f1609276fb509b4/obelisk-upgradedeleted

No changes to the content.

migration/13f6767460e94079cdfa6d5e1df79ecb-c106f9398d5c203a1a296b85c7411bf9/obelisk-handoffdeleted

No changes to the content.

migration/13f6767460e94079cdfa6d5e1df79ecb-c106f9398d5c203a1a296b85c7411bf9/obelisk-upgradedeleted

No changes to the content.

migration/145650b66e83adf5bdb8261593076379-e2be519915794ef130249f2be7640382/obelisk-handoffdeleted

No changes to the content.

migration/145650b66e83adf5bdb8261593076379-e2be519915794ef130249f2be7640382/obelisk-upgradedeleted

No changes to the content.

migration/14840816db4b5cfd5580ae099022604a-aaf979dd0121603a8b48127e1ea47c7d/obelisk-handoffdeleted

No changes to the content.

migration/14840816db4b5cfd5580ae099022604a-aaf979dd0121603a8b48127e1ea47c7d/obelisk-upgradedeleted

No changes to the content.

migration/15f3f3f517b38664131b85da0594522f-9715967793be68dfd8c9a7d631f8d589/obelisk-handoffdeleted

No changes to the content.

migration/15f3f3f517b38664131b85da0594522f-9715967793be68dfd8c9a7d631f8d589/obelisk-upgradedeleted

No changes to the content.

migration/1629d0d70e360df6b2280fac36d21e8a-a825fbb74e8d050a5ce10ec4c62b83f5/obelisk-handoffdeleted

No changes to the content.

migration/1629d0d70e360df6b2280fac36d21e8a-a825fbb74e8d050a5ce10ec4c62b83f5/obelisk-upgradedeleted

No changes to the content.

migration/166c5f8e4a0f1dfd227b075a96237386-a5904e3a899e346fe2fe26314f69c075/obelisk-handoffdeleted

No changes to the content.

migration/166c5f8e4a0f1dfd227b075a96237386-a5904e3a899e346fe2fe26314f69c075/obelisk-upgradedeleted

No changes to the content.

migration/16b24e1a12b93ea83d7656a09d5e3338-8a64ec5f2ee43d69607499f085560857/obelisk-handoffdeleted

No changes to the content.

migration/16b24e1a12b93ea83d7656a09d5e3338-8a64ec5f2ee43d69607499f085560857/obelisk-upgradedeleted

No changes to the content.

migration/17089ea0edc0cf4b6f616936f8a06174-a34d758508a0a5d08bc10e76482c4d11/obelisk-handoffdeleted

No changes to the content.

migration/17089ea0edc0cf4b6f616936f8a06174-a34d758508a0a5d08bc10e76482c4d11/obelisk-upgradedeleted

No changes to the content.

migration/172e629829334d2b33cda8d3b5e0b148-a808a04519bbf2874e41028ded9c180c/obelisk-handoffdeleted

No changes to the content.

migration/172e629829334d2b33cda8d3b5e0b148-a808a04519bbf2874e41028ded9c180c/obelisk-upgradedeleted

No changes to the content.

migration/174fa1072ee767be39b7b01aecea5714-6566f0555737425bae9106d1a4a0a2dd/obelisk-handoffdeleted

No changes to the content.

migration/174fa1072ee767be39b7b01aecea5714-6566f0555737425bae9106d1a4a0a2dd/obelisk-upgradedeleted

No changes to the content.

migration/1859cc62bb2f89f528bb2aa170c36e84-be5a7b436cef0ae35cb074700d5f0d00/obelisk-handoffdeleted

No changes to the content.

migration/1859cc62bb2f89f528bb2aa170c36e84-be5a7b436cef0ae35cb074700d5f0d00/obelisk-upgradedeleted

No changes to the content.

migration/190460dabd2b9773c3fe81902d0c8a62-e7385c9eae2b807a483b73be4295b207/obelisk-handoffdeleted

No changes to the content.

migration/190460dabd2b9773c3fe81902d0c8a62-e7385c9eae2b807a483b73be4295b207/obelisk-upgradedeleted

No changes to the content.

migration/1a08b154ae5f898992128e229090c4d8-4e95e2f8ef50420371b71022c644e25d/obelisk-handoffdeleted

No changes to the content.

migration/1a08b154ae5f898992128e229090c4d8-4e95e2f8ef50420371b71022c644e25d/obelisk-upgradedeleted

No changes to the content.

migration/1a97559d049bf85cebb762b7e7b70db1-5cb98d0250bf5224b94e544a5140a54c/obelisk-handoffdeleted

No changes to the content.

migration/1a97559d049bf85cebb762b7e7b70db1-5cb98d0250bf5224b94e544a5140a54c/obelisk-upgradedeleted

No changes to the content.

migration/1ada2d50d7847a12dbe29df4097b5bdc-11a5917ea91e021f1fa541a2fe158c80/obelisk-handoffdeleted

No changes to the content.

migration/1ada2d50d7847a12dbe29df4097b5bdc-11a5917ea91e021f1fa541a2fe158c80/obelisk-upgradedeleted

No changes to the content.

migration/1b1686b03b41bd840ff46776cec7b33a-31a676fd9e1f69bd07380480ec879da0/obelisk-handoffdeleted

No changes to the content.

migration/1b1686b03b41bd840ff46776cec7b33a-31a676fd9e1f69bd07380480ec879da0/obelisk-upgradedeleted

No changes to the content.

migration/1c1c3f2b4426d5d26377eef08dbccb3c-29abdd56a2dbbf3a2a0715210d441d06/obelisk-handoffdeleted

No changes to the content.

migration/1c1c3f2b4426d5d26377eef08dbccb3c-29abdd56a2dbbf3a2a0715210d441d06/obelisk-upgradedeleted

No changes to the content.

migration/1c2c93819c07f33ad899e39ec6769c3c-909b6b2066cbdc991e6c16455f13637c/obelisk-handoffdeleted

No changes to the content.

migration/1c2c93819c07f33ad899e39ec6769c3c-909b6b2066cbdc991e6c16455f13637c/obelisk-upgradedeleted

No changes to the content.

migration/1c4fc23cbf5653613c6060668e065f37-5b252c24612c2ba868580add9d9c19e3/obelisk-handoffdeleted

No changes to the content.

migration/1c4fc23cbf5653613c6060668e065f37-5b252c24612c2ba868580add9d9c19e3/obelisk-upgradedeleted

No changes to the content.

migration/1c9bdb5c544f2e5432f549653a61dabe-20926beb4c30e2efa819d23e5694645e/obelisk-handoffdeleted

No changes to the content.

migration/1c9bdb5c544f2e5432f549653a61dabe-20926beb4c30e2efa819d23e5694645e/obelisk-upgradedeleted

No changes to the content.

migration/1cc8d98f6f61441570fdde2d697e6e3c-69fafe6ab155ff215b6d9d330f700ba1/obelisk-handoffdeleted

No changes to the content.

migration/1cc8d98f6f61441570fdde2d697e6e3c-69fafe6ab155ff215b6d9d330f700ba1/obelisk-upgradedeleted

No changes to the content.

migration/1d084e187591225f0e8fa6fa824f8863-02f532fd8bb64a167a5349c2ba8e3331/obelisk-handoffdeleted

No changes to the content.

migration/1d084e187591225f0e8fa6fa824f8863-02f532fd8bb64a167a5349c2ba8e3331/obelisk-upgradedeleted

No changes to the content.

migration/1df871cede0758cabe43971d9091279d-0b2cab546a1526414096980fca85d0d3/obelisk-handoffdeleted

No changes to the content.

migration/1df871cede0758cabe43971d9091279d-0b2cab546a1526414096980fca85d0d3/obelisk-upgradedeleted

No changes to the content.

migration/1e36dc8817e2784df36d643b7499092d-ba0ccd5ef6110f6c5133d9d6ea6277f0/obelisk-handoffdeleted

No changes to the content.

migration/1e36dc8817e2784df36d643b7499092d-ba0ccd5ef6110f6c5133d9d6ea6277f0/obelisk-upgradedeleted

No changes to the content.

migration/1e376437f069662df26178e4a7873190-ca5ee8f372ecb07b09283081f0298733/obelisk-handoffdeleted

No changes to the content.

migration/1e376437f069662df26178e4a7873190-ca5ee8f372ecb07b09283081f0298733/obelisk-upgradedeleted

No changes to the content.

migration/1f09fcf196bfe90ed52f113c38ffbfdb-d16784e9a2d93db7f953941e3003fa8c/obelisk-handoffdeleted

No changes to the content.

migration/1f09fcf196bfe90ed52f113c38ffbfdb-d16784e9a2d93db7f953941e3003fa8c/obelisk-upgradedeleted

No changes to the content.

migration/1f5b6e2a19c87d3820b953f942ab4a27-8b098f49e1fd1aa10ca22b9dc312644e/obelisk-handoffdeleted

No changes to the content.

migration/1f5b6e2a19c87d3820b953f942ab4a27-8b098f49e1fd1aa10ca22b9dc312644e/obelisk-upgradedeleted

No changes to the content.

migration/1f7fb90cb1e558f5285b2d19a25a1078-5a98cdb6c195e88beac878a3f311c5b5/obelisk-handoffdeleted

No changes to the content.

migration/1f7fb90cb1e558f5285b2d19a25a1078-5a98cdb6c195e88beac878a3f311c5b5/obelisk-upgradedeleted

No changes to the content.

migration/1fe00204f9d2cd653ff2894eae3d9356-4b3f45ce8aeb17ef18d1d9502b74bb7e/obelisk-handoffdeleted

No changes to the content.

migration/1fe00204f9d2cd653ff2894eae3d9356-4b3f45ce8aeb17ef18d1d9502b74bb7e/obelisk-upgradedeleted

No changes to the content.

migration/20926beb4c30e2efa819d23e5694645e-212ead9571b83b8164b3f18d2537d52b/obelisk-handoffdeleted

No changes to the content.

migration/20926beb4c30e2efa819d23e5694645e-212ead9571b83b8164b3f18d2537d52b/obelisk-upgradedeleted

No changes to the content.

migration/212ead9571b83b8164b3f18d2537d52b-3bf8e28473fb05791c5790f8906e2609/obelisk-handoffdeleted

No changes to the content.

migration/212ead9571b83b8164b3f18d2537d52b-3bf8e28473fb05791c5790f8906e2609/obelisk-upgradedeleted

No changes to the content.

migration/214979923f2d7e6278856493c1978fdc-13f6767460e94079cdfa6d5e1df79ecb/obelisk-handoffdeleted

No changes to the content.

migration/214979923f2d7e6278856493c1978fdc-13f6767460e94079cdfa6d5e1df79ecb/obelisk-upgradedeleted

No changes to the content.

migration/215b6810b09f219a5cb3842aacc88432-2ef4f9cce6d15ae62d5112d3c224eb7a/obelisk-handoffdeleted

No changes to the content.

migration/215b6810b09f219a5cb3842aacc88432-2ef4f9cce6d15ae62d5112d3c224eb7a/obelisk-upgradedeleted

No changes to the content.

migration/2164344be67da5d0e57052c15f30646d-0c9826e42d5d4fa9988c7db53722826e/obelisk-handoffdeleted

No changes to the content.

migration/2164344be67da5d0e57052c15f30646d-0c9826e42d5d4fa9988c7db53722826e/obelisk-upgradedeleted

No changes to the content.

migration/237aeb7eee0ffed230234ee04e49569f-55cf43fb0d3868040c9efbf2f92d538a/obelisk-handoffdeleted

No changes to the content.

migration/237aeb7eee0ffed230234ee04e49569f-55cf43fb0d3868040c9efbf2f92d538a/obelisk-upgradedeleted

No changes to the content.

migration/23af4d9671962484de53f537a0626d83-7ce32302cfbba8b7567a05144057f8a3/obelisk-handoffdeleted

No changes to the content.

migration/23af4d9671962484de53f537a0626d83-7ce32302cfbba8b7567a05144057f8a3/obelisk-upgradedeleted

No changes to the content.

migration/24e0d027f4160a6478c1356e51f419cf-4e3e6e8b9d0f4194842e530438ff686f/obelisk-handoffdeleted

No changes to the content.

migration/24e0d027f4160a6478c1356e51f419cf-4e3e6e8b9d0f4194842e530438ff686f/obelisk-upgradedeleted

No changes to the content.

migration/24f151a674662ac47845237d7a9f6a4f-4fe321cf196b9cd25210c35e09e09d8f/obelisk-handoffdeleted

No changes to the content.

migration/24f151a674662ac47845237d7a9f6a4f-4fe321cf196b9cd25210c35e09e09d8f/obelisk-upgradedeleted

No changes to the content.

migration/2543866165016a449562ea7a1ee36f6f-1a08b154ae5f898992128e229090c4d8/obelisk-handoffdeleted

No changes to the content.

migration/2543866165016a449562ea7a1ee36f6f-1a08b154ae5f898992128e229090c4d8/obelisk-upgradedeleted

No changes to the content.

migration/25615a274650370633e8083ed19fbdd0-80cb6b08443d55bb512e4a35b4768b72/obelisk-handoffdeleted

No changes to the content.

migration/25615a274650370633e8083ed19fbdd0-80cb6b08443d55bb512e4a35b4768b72/obelisk-upgradedeleted

No changes to the content.

migration/2600ab2ec96d3177d2a6b3462e09862d-e2b2d878b0ba6eb653b194523bf0a0e0/obelisk-handoffdeleted

No changes to the content.

migration/2600ab2ec96d3177d2a6b3462e09862d-e2b2d878b0ba6eb653b194523bf0a0e0/obelisk-upgradedeleted

No changes to the content.

migration/2619464637b85cb35376393fe612ddae-a8ebe201ab7a7b0211de41b14a95192e/obelisk-handoffdeleted

No changes to the content.

migration/2619464637b85cb35376393fe612ddae-a8ebe201ab7a7b0211de41b14a95192e/obelisk-upgradedeleted

No changes to the content.

migration/26a2491fc8a9658751c1511c777a67bd-470df6504156dc940b8e7f89c148e619/obelisk-handoffdeleted

No changes to the content.

migration/26a2491fc8a9658751c1511c777a67bd-470df6504156dc940b8e7f89c148e619/obelisk-upgradedeleted

No changes to the content.

migration/270b3b3f7bc510c692e3253a895f122a-c2d4eeb20f2b319a2d9dc5b6b0762f83/obelisk-handoffdeleted

No changes to the content.

migration/270b3b3f7bc510c692e3253a895f122a-c2d4eeb20f2b319a2d9dc5b6b0762f83/obelisk-upgradedeleted

No changes to the content.

migration/2773d4a82ca59b48faf036755e163a5f-71c6959cf98e05d356ff798ada6db2b8/obelisk-handoffdeleted

No changes to the content.

migration/2773d4a82ca59b48faf036755e163a5f-71c6959cf98e05d356ff798ada6db2b8/obelisk-upgradedeleted

No changes to the content.

migration/28a6ada033c86e5ae914cc31cecb6239-90b4e20464e08ade5f215f2a4ea28cc6/obelisk-handoffdeleted

No changes to the content.

migration/28a6ada033c86e5ae914cc31cecb6239-90b4e20464e08ade5f215f2a4ea28cc6/obelisk-upgradedeleted

No changes to the content.

migration/28c5fec3b7b0b14b3625d5c8f60bcf68-4509e2a908da9e497fa67acacdd107b6/obelisk-handoffdeleted

No changes to the content.

migration/28c5fec3b7b0b14b3625d5c8f60bcf68-4509e2a908da9e497fa67acacdd107b6/obelisk-upgradedeleted

No changes to the content.

migration/28e25b7a8812869a709579cd34e7bcb4-2543866165016a449562ea7a1ee36f6f/obelisk-handoffdeleted

No changes to the content.

migration/28e25b7a8812869a709579cd34e7bcb4-2543866165016a449562ea7a1ee36f6f/obelisk-upgradedeleted

No changes to the content.

migration/2913c440c7ad7731aae96e60a86bf7a8-a08aebb6f40fb45d174b229532314ac4/obelisk-handoffdeleted

No changes to the content.

migration/2913c440c7ad7731aae96e60a86bf7a8-a08aebb6f40fb45d174b229532314ac4/obelisk-upgradedeleted

No changes to the content.

migration/29abdd56a2dbbf3a2a0715210d441d06-51c7d001730ddd3d76e0c8bb57038773/obelisk-handoffdeleted

No changes to the content.

migration/29abdd56a2dbbf3a2a0715210d441d06-51c7d001730ddd3d76e0c8bb57038773/obelisk-upgradedeleted

No changes to the content.

migration/29d9b8b8ae9698888f3ea90b10ff5e92-1ada2d50d7847a12dbe29df4097b5bdc/obelisk-handoffdeleted

No changes to the content.

migration/29d9b8b8ae9698888f3ea90b10ff5e92-1ada2d50d7847a12dbe29df4097b5bdc/obelisk-upgradedeleted

No changes to the content.

migration/29fd07af89cc31526fca00226ff52a82-50b85e79010ad50ee275eaeba0df6f8d/obelisk-handoffdeleted

No changes to the content.

migration/29fd07af89cc31526fca00226ff52a82-50b85e79010ad50ee275eaeba0df6f8d/obelisk-upgradedeleted

No changes to the content.

migration/2ba356b187db8db13b8aa40f43ca025f-3c1fc501da00f467c9a48a1ddee2c2b0/obelisk-handoffdeleted

No changes to the content.

migration/2ba356b187db8db13b8aa40f43ca025f-3c1fc501da00f467c9a48a1ddee2c2b0/obelisk-upgradedeleted

No changes to the content.

migration/2bdd4221307cafa3e98c4d3017cdc912-5f6fe243beb9fcc0c4117536022fc14c/obelisk-handoffdeleted

No changes to the content.

migration/2bdd4221307cafa3e98c4d3017cdc912-5f6fe243beb9fcc0c4117536022fc14c/obelisk-upgradedeleted

No changes to the content.

migration/2c1521e5a5be64e6d28a9fdae950cd76-92ab733e8991f12cc12148f8d4e1b35d/obelisk-handoffdeleted

No changes to the content.

migration/2c1521e5a5be64e6d28a9fdae950cd76-92ab733e8991f12cc12148f8d4e1b35d/obelisk-upgradedeleted

No changes to the content.

migration/2ccf977797628dc3b1c002927fedc7a8-46f9c6c66e2bd8980402b6117ca40965/obelisk-handoffdeleted

No changes to the content.

migration/2ccf977797628dc3b1c002927fedc7a8-46f9c6c66e2bd8980402b6117ca40965/obelisk-upgradedeleted

No changes to the content.

migration/2df092178e167b474dd08dfa46ec3a49-9c94cd459a25b5c2de56067c8fdac620/obelisk-handoffdeleted

No changes to the content.

migration/2df092178e167b474dd08dfa46ec3a49-9c94cd459a25b5c2de56067c8fdac620/obelisk-upgradedeleted

No changes to the content.

migration/2e3e85cc59aa31f24f18c027542c0510-47357c6c23f049241902bf2e2e686ac8/obelisk-handoffdeleted

No changes to the content.

migration/2e3e85cc59aa31f24f18c027542c0510-47357c6c23f049241902bf2e2e686ac8/obelisk-upgradedeleted

No changes to the content.

migration/2e7cdc2bea08bb2358219ddefef372e0-a00870cfca85ff8dae5db3a78f5a227d/obelisk-handoffdeleted

No changes to the content.

migration/2e7cdc2bea08bb2358219ddefef372e0-a00870cfca85ff8dae5db3a78f5a227d/obelisk-upgradedeleted

No changes to the content.

migration/2e9a04a228106f62128ea5bd19d6b25e-947784563e3a27cf6486bed9a3c52f15/obelisk-handoffdeleted

No changes to the content.

migration/2e9a04a228106f62128ea5bd19d6b25e-947784563e3a27cf6486bed9a3c52f15/obelisk-upgradedeleted

No changes to the content.

migration/2eb907820012f77e60350430d89631fe-494be5819cd601fd2f0c20e1b23b84a3/obelisk-handoffdeleted

No changes to the content.

migration/2eb907820012f77e60350430d89631fe-494be5819cd601fd2f0c20e1b23b84a3/obelisk-upgradedeleted

No changes to the content.

migration/2ef4f9cce6d15ae62d5112d3c224eb7a-a080b8549e32f21fec11084f4ab1e052/obelisk-handoffdeleted

No changes to the content.

migration/2ef4f9cce6d15ae62d5112d3c224eb7a-a080b8549e32f21fec11084f4ab1e052/obelisk-upgradedeleted

No changes to the content.

migration/2f3ecb5cdb0ab839a49271d91dd7852a-f9ad863c0bebc103f8b81afdf82e6293/obelisk-handoffdeleted

No changes to the content.

migration/2f3ecb5cdb0ab839a49271d91dd7852a-f9ad863c0bebc103f8b81afdf82e6293/obelisk-upgradedeleted

No changes to the content.

migration/2f928f9c4a137186f808a231c9e3c141-9e61f37dd79310b71c80ee166aeb4e80/obelisk-handoffdeleted

No changes to the content.

migration/2f928f9c4a137186f808a231c9e3c141-9e61f37dd79310b71c80ee166aeb4e80/obelisk-upgradedeleted

No changes to the content.

migration/315cd79f97dae2f3669551dc03e0fd27-c801cbcf925c0a7b084ef152e3c08f8e/obelisk-handoffdeleted

No changes to the content.

migration/315cd79f97dae2f3669551dc03e0fd27-c801cbcf925c0a7b084ef152e3c08f8e/obelisk-upgradedeleted

No changes to the content.

migration/31a676fd9e1f69bd07380480ec879da0-9223532a537f698ef36f4dce6e922a6b/obelisk-handoffdeleted

No changes to the content.

migration/31a676fd9e1f69bd07380480ec879da0-9223532a537f698ef36f4dce6e922a6b/obelisk-upgradedeleted

No changes to the content.

migration/338b92f88c49c7c3a1d8ec231d9f7189-a4477746ae1a7024bc3cd0807180d418/obelisk-handoffdeleted

No changes to the content.

migration/338b92f88c49c7c3a1d8ec231d9f7189-a4477746ae1a7024bc3cd0807180d418/obelisk-upgradedeleted

No changes to the content.

migration/33da5c0e6705843afa6e39e65bfa0564-3ec562b7333839d48e9523aec595f3ab/obelisk-handoffdeleted

No changes to the content.

migration/33da5c0e6705843afa6e39e65bfa0564-3ec562b7333839d48e9523aec595f3ab/obelisk-upgradedeleted

No changes to the content.

migration/34d14d4a444d3bf1487ada6129815df4-afbd010add526d309dccee6895e42d0d/obelisk-handoffdeleted

No changes to the content.

migration/34d14d4a444d3bf1487ada6129815df4-afbd010add526d309dccee6895e42d0d/obelisk-upgradedeleted

No changes to the content.

migration/35acc1e0c4d9c02d60abd116f3df84ee-ffa62158ed6fdece012980e4ad25e6ac/obelisk-handoffdeleted

No changes to the content.

migration/35acc1e0c4d9c02d60abd116f3df84ee-ffa62158ed6fdece012980e4ad25e6ac/obelisk-upgradedeleted

No changes to the content.

migration/367616bd36eda757f251a5e8e9096acc-ddaa8e0e42a1ef00154d580a390c9f17/obelisk-handoffdeleted

No changes to the content.

migration/367616bd36eda757f251a5e8e9096acc-ddaa8e0e42a1ef00154d580a390c9f17/obelisk-upgradedeleted

No changes to the content.

migration/36cdb1c744c3036c2932f01d5fadd9f5-e7b566495114e160f1f4d722b7ed8174/obelisk-handoffdeleted

No changes to the content.

migration/36cdb1c744c3036c2932f01d5fadd9f5-e7b566495114e160f1f4d722b7ed8174/obelisk-upgradedeleted

No changes to the content.

migration/375acf7f2a3b3c487da2a6b30735d74d-3b614d291e262d0f281b54ff42a6bb66/obelisk-handoffdeleted

No changes to the content.

migration/375acf7f2a3b3c487da2a6b30735d74d-3b614d291e262d0f281b54ff42a6bb66/obelisk-upgradedeleted

No changes to the content.

migration/37c2ed0ba2cd54c0ec29eae9043bc4c8-190460dabd2b9773c3fe81902d0c8a62/obelisk-handoffdeleted

No changes to the content.

migration/37c2ed0ba2cd54c0ec29eae9043bc4c8-190460dabd2b9773c3fe81902d0c8a62/obelisk-upgradedeleted

No changes to the content.

migration/388d7d29a65c1713e07a654e91eb9caf-b6ffce85249f30616da76334c7bbec6e/obelisk-handoffdeleted

No changes to the content.

migration/388d7d29a65c1713e07a654e91eb9caf-b6ffce85249f30616da76334c7bbec6e/obelisk-upgradedeleted

No changes to the content.

migration/39df6544d6b035d4c77cc829729f9c19-9f6c8fd80ab3ff2dcc48bfd211c8b761/obelisk-handoffdeleted

No changes to the content.

migration/39df6544d6b035d4c77cc829729f9c19-9f6c8fd80ab3ff2dcc48bfd211c8b761/obelisk-upgradedeleted

No changes to the content.

migration/3a207630aa67e5df48d2b87d34db616b-8adb921f4dbb9d363bf6647d304e02fe/obelisk-handoffdeleted

No changes to the content.

migration/3a207630aa67e5df48d2b87d34db616b-8adb921f4dbb9d363bf6647d304e02fe/obelisk-upgradedeleted

No changes to the content.

migration/3b614d291e262d0f281b54ff42a6bb66-2e9a04a228106f62128ea5bd19d6b25e/obelisk-handoffdeleted

No changes to the content.

migration/3b614d291e262d0f281b54ff42a6bb66-2e9a04a228106f62128ea5bd19d6b25e/obelisk-upgradedeleted

No changes to the content.

migration/3bc53f3a28cb8f403cc41c11a37eec5d-cd86427cc2d5b2e931d7ab03deb19d20/obelisk-handoffdeleted

No changes to the content.

migration/3bc53f3a28cb8f403cc41c11a37eec5d-cd86427cc2d5b2e931d7ab03deb19d20/obelisk-upgradedeleted

No changes to the content.

migration/3bf8e28473fb05791c5790f8906e2609-45185a6f053557f93a13cb8cd03963a7/obelisk-handoffdeleted

No changes to the content.

migration/3bf8e28473fb05791c5790f8906e2609-45185a6f053557f93a13cb8cd03963a7/obelisk-upgradedeleted

No changes to the content.

migration/3c1fc501da00f467c9a48a1ddee2c2b0-cd5b54d21dd0fb868f48624d41021f47/obelisk-handoffdeleted

No changes to the content.

migration/3c1fc501da00f467c9a48a1ddee2c2b0-cd5b54d21dd0fb868f48624d41021f47/obelisk-upgradedeleted

No changes to the content.

migration/3c4b3152f0608d23d07240e2df3ff8da-c6baede3962454713b73acefcc92fe75/obelisk-handoffdeleted

No changes to the content.

migration/3c4b3152f0608d23d07240e2df3ff8da-c6baede3962454713b73acefcc92fe75/obelisk-upgradedeleted

No changes to the content.

migration/3c7755e495f20cfac5e4dabe78644c5a-51e25cf740f064faa0a29b8e2afcc109/obelisk-handoffdeleted

No changes to the content.

migration/3c7755e495f20cfac5e4dabe78644c5a-51e25cf740f064faa0a29b8e2afcc109/obelisk-upgradedeleted

No changes to the content.

migration/3c80eccfe80d0abd36b07bb11e69fc7a-b4f6596f2c16811442d8bb2961fbb721/obelisk-handoffdeleted

No changes to the content.

migration/3c80eccfe80d0abd36b07bb11e69fc7a-b4f6596f2c16811442d8bb2961fbb721/obelisk-upgradedeleted

No changes to the content.

migration/3cb52c2838303a362e9efb7c7eea37bd-aeafaa5d20bab4439a5d31f29023a839/obelisk-handoffdeleted

No changes to the content.

migration/3cb52c2838303a362e9efb7c7eea37bd-aeafaa5d20bab4439a5d31f29023a839/obelisk-upgradedeleted

No changes to the content.

migration/3da702ef7f531ad6db874ac3f85e9c06-73bcf3ed6593d074bd097cd43f5145d1/obelisk-handoffdeleted

No changes to the content.

migration/3da702ef7f531ad6db874ac3f85e9c06-73bcf3ed6593d074bd097cd43f5145d1/obelisk-upgradedeleted

No changes to the content.

migration/3da7d4a3b507d18097a90becf4dde9aa-e1ef432db54d9a6daa9bdeeb543262ae/obelisk-handoffdeleted

No changes to the content.

migration/3da7d4a3b507d18097a90becf4dde9aa-e1ef432db54d9a6daa9bdeeb543262ae/obelisk-upgradedeleted

No changes to the content.

migration/3daecb03985f83d8af466a9e0541782b-a2665cfd303a4a34a7bfa3b7d0d264bb/obelisk-handoffdeleted

No changes to the content.

migration/3daecb03985f83d8af466a9e0541782b-a2665cfd303a4a34a7bfa3b7d0d264bb/obelisk-upgradedeleted

No changes to the content.

migration/3e253c6beb567ba8f4c8086a76b70645-d6cacd7f4fab95c4b6aa2d6c1a4ad2a0/obelisk-handoffdeleted

No changes to the content.

migration/3e253c6beb567ba8f4c8086a76b70645-d6cacd7f4fab95c4b6aa2d6c1a4ad2a0/obelisk-upgradedeleted

No changes to the content.

migration/3e763ebe16cc3a261f5776ab1f1f6d9a-583ec22b9af66e8f629ee404307eb2dc/obelisk-handoffdeleted

No changes to the content.

migration/3e763ebe16cc3a261f5776ab1f1f6d9a-583ec22b9af66e8f629ee404307eb2dc/obelisk-upgradedeleted

No changes to the content.

migration/3e8a6968585d3d60f3b13652a386aec0-c118e1ee09ec8d9aa3edf04e211ae035/obelisk-handoffdeleted

No changes to the content.

migration/3e8a6968585d3d60f3b13652a386aec0-c118e1ee09ec8d9aa3edf04e211ae035/obelisk-upgradedeleted

No changes to the content.

migration/3ec562b7333839d48e9523aec595f3ab-7b9c28d09bd962e89b9715500f9e184c/obelisk-handoffdeleted

No changes to the content.

migration/3ec562b7333839d48e9523aec595f3ab-7b9c28d09bd962e89b9715500f9e184c/obelisk-upgradedeleted

No changes to the content.

migration/3f0687592a77c0c66193652e9cd981fd-fb81153791e49cd00850e91ff7418018/obelisk-handoffdeleted

No changes to the content.

migration/3f0687592a77c0c66193652e9cd981fd-fb81153791e49cd00850e91ff7418018/obelisk-upgradedeleted

No changes to the content.

migration/3f23549fba6f8e67ba36b4405e8680b3-a6633fc9687566aa84c3d5d5e2bff4fd/obelisk-handoffdeleted

No changes to the content.

migration/3f23549fba6f8e67ba36b4405e8680b3-a6633fc9687566aa84c3d5d5e2bff4fd/obelisk-upgradedeleted

No changes to the content.

migration/41e3ba178b727517aa1cedc8815abe86-1d084e187591225f0e8fa6fa824f8863/obelisk-handoffdeleted

No changes to the content.

migration/41e3ba178b727517aa1cedc8815abe86-1d084e187591225f0e8fa6fa824f8863/obelisk-upgradedeleted

No changes to the content.

migration/4205857df2e234a476ad56f84a33e6ed-db327f87e60d4e59bdbfd482e5abe985/obelisk-handoffdeleted

No changes to the content.

migration/4205857df2e234a476ad56f84a33e6ed-db327f87e60d4e59bdbfd482e5abe985/obelisk-upgradedeleted

No changes to the content.

migration/423088b98df50b986c9197af83c42a25-3a207630aa67e5df48d2b87d34db616b/obelisk-handoffdeleted

No changes to the content.

migration/423088b98df50b986c9197af83c42a25-3a207630aa67e5df48d2b87d34db616b/obelisk-upgradedeleted

No changes to the content.

migration/42357310c09e345f9360259c6c4102f2-ae8862f8b7292690c852111ca5659ce9/obelisk-handoffdeleted

No changes to the content.

migration/42357310c09e345f9360259c6c4102f2-ae8862f8b7292690c852111ca5659ce9/obelisk-upgradedeleted

No changes to the content.

migration/4344c1bd0ef04ebc055d5252f58b0bef-2f3ecb5cdb0ab839a49271d91dd7852a/obelisk-handoffdeleted

No changes to the content.

migration/4344c1bd0ef04ebc055d5252f58b0bef-2f3ecb5cdb0ab839a49271d91dd7852a/obelisk-upgradedeleted

No changes to the content.

migration/4509e2a908da9e497fa67acacdd107b6-1fe00204f9d2cd653ff2894eae3d9356/obelisk-handoffdeleted

No changes to the content.

migration/4509e2a908da9e497fa67acacdd107b6-1fe00204f9d2cd653ff2894eae3d9356/obelisk-upgradedeleted

No changes to the content.

migration/45185a6f053557f93a13cb8cd03963a7-cffcc6cab6080a35b7bf7c5c7facd6bc/obelisk-handoffdeleted

No changes to the content.

migration/45185a6f053557f93a13cb8cd03963a7-cffcc6cab6080a35b7bf7c5c7facd6bc/obelisk-upgradedeleted

No changes to the content.

migration/455279b6974b96a673613cd0ccc8ed54-b3ff195b0a90ef5900f9cef2ba75f2fe/obelisk-handoffdeleted

No changes to the content.

migration/455279b6974b96a673613cd0ccc8ed54-b3ff195b0a90ef5900f9cef2ba75f2fe/obelisk-upgradedeleted

No changes to the content.

migration/463646ba21b356f612539ea34178adf9-b3b107d406a6a7675cd5b9f52e5f7d8e/obelisk-handoffdeleted

No changes to the content.

migration/463646ba21b356f612539ea34178adf9-b3b107d406a6a7675cd5b9f52e5f7d8e/obelisk-upgradedeleted

No changes to the content.

migration/466a19f9cfa2a103467fe6627225d27f-c67f206b6d2626eb6d36b00122b52784/obelisk-handoffdeleted

No changes to the content.

migration/466a19f9cfa2a103467fe6627225d27f-c67f206b6d2626eb6d36b00122b52784/obelisk-upgradedeleted

No changes to the content.

migration/469a31d20d69da72e6a3a3ea2bb02f9d-75c9cd9763d0ed89c17d455f49d66a4f/obelisk-handoffdeleted

No changes to the content.

migration/469a31d20d69da72e6a3a3ea2bb02f9d-75c9cd9763d0ed89c17d455f49d66a4f/obelisk-upgradedeleted

No changes to the content.

migration/46aed07c1a61476dd245ff8e74c0559f-73e2573d9074884d7ae83106d55ad229/obelisk-handoffdeleted

No changes to the content.

migration/46aed07c1a61476dd245ff8e74c0559f-73e2573d9074884d7ae83106d55ad229/obelisk-upgradedeleted

No changes to the content.

migration/46f9c6c66e2bd8980402b6117ca40965-463646ba21b356f612539ea34178adf9/obelisk-handoffdeleted

No changes to the content.

migration/46f9c6c66e2bd8980402b6117ca40965-463646ba21b356f612539ea34178adf9/obelisk-upgradedeleted

No changes to the content.

migration/470df6504156dc940b8e7f89c148e619-a5297d8457aa4c327f35d4697f6cb66f/obelisk-handoffdeleted

No changes to the content.

migration/470df6504156dc940b8e7f89c148e619-a5297d8457aa4c327f35d4697f6cb66f/obelisk-upgradedeleted

No changes to the content.

migration/47357c6c23f049241902bf2e2e686ac8-d62d6d443d9c2261b7e09664398aa005/obelisk-handoffdeleted

No changes to the content.

migration/47357c6c23f049241902bf2e2e686ac8-d62d6d443d9c2261b7e09664398aa005/obelisk-upgradedeleted

No changes to the content.

migration/475f9a0d63e84e9cf13b8be3986cb603-b95c8d049256fb7360ca14b12acd8544/obelisk-handoffdeleted

No changes to the content.

migration/475f9a0d63e84e9cf13b8be3986cb603-b95c8d049256fb7360ca14b12acd8544/obelisk-upgradedeleted

No changes to the content.

migration/477a0bb12b48357d1e2b415c91d904e3-486d5218951605d14ec4a1046d3fe83e/obelisk-handoffdeleted

No changes to the content.

migration/477a0bb12b48357d1e2b415c91d904e3-486d5218951605d14ec4a1046d3fe83e/obelisk-upgradedeleted

No changes to the content.

migration/486d5218951605d14ec4a1046d3fe83e-90489c1a9f7edd46a070d6474dceac86/obelisk-handoffdeleted

No changes to the content.

migration/486d5218951605d14ec4a1046d3fe83e-90489c1a9f7edd46a070d6474dceac86/obelisk-upgradedeleted

No changes to the content.

migration/48c027da19d895ba03e7b9120f771291-29fd07af89cc31526fca00226ff52a82/obelisk-handoffdeleted

No changes to the content.

migration/48c027da19d895ba03e7b9120f771291-29fd07af89cc31526fca00226ff52a82/obelisk-upgradedeleted

No changes to the content.

migration/494be5819cd601fd2f0c20e1b23b84a3-c66bc5ba27dec52d144ceb0aa429e449/obelisk-handoffdeleted

No changes to the content.

migration/494be5819cd601fd2f0c20e1b23b84a3-c66bc5ba27dec52d144ceb0aa429e449/obelisk-upgradedeleted

No changes to the content.

migration/4a037879b8a542f1590cbb87b0242331-4344c1bd0ef04ebc055d5252f58b0bef/obelisk-handoffdeleted

No changes to the content.

migration/4a037879b8a542f1590cbb87b0242331-4344c1bd0ef04ebc055d5252f58b0bef/obelisk-upgradedeleted

No changes to the content.

migration/4ab915b764f38a1b0b4ae6f619f5c3fa-59e4a192c611a2a9f6736afde9fe1a0e/obelisk-handoffdeleted

No changes to the content.

migration/4ab915b764f38a1b0b4ae6f619f5c3fa-59e4a192c611a2a9f6736afde9fe1a0e/obelisk-upgradedeleted

No changes to the content.

migration/4ace4414d71235a291f7148f80a0b0f5-9705509619667aacf799e91927c16dc8/obelisk-handoffdeleted

No changes to the content.

migration/4ace4414d71235a291f7148f80a0b0f5-9705509619667aacf799e91927c16dc8/obelisk-upgradedeleted

No changes to the content.

migration/4aefa80392582ec03a19f946e752d331-cb98f93880e6dea74014976977d6eb93/obelisk-handoffdeleted

No changes to the content.

migration/4aefa80392582ec03a19f946e752d331-cb98f93880e6dea74014976977d6eb93/obelisk-upgradedeleted

No changes to the content.

migration/4b3f45ce8aeb17ef18d1d9502b74bb7e-4efbe4a73c260cca09fed7169e82a7ff/obelisk-handoffdeleted

No changes to the content.

migration/4b3f45ce8aeb17ef18d1d9502b74bb7e-4efbe4a73c260cca09fed7169e82a7ff/obelisk-upgradedeleted

No changes to the content.

migration/4b7a36dce2c1cf94554e12d8a7903269-dd6ca52a58ea6cda7b3eaa2e87bb13d9/obelisk-handoffdeleted

No changes to the content.

migration/4b7a36dce2c1cf94554e12d8a7903269-dd6ca52a58ea6cda7b3eaa2e87bb13d9/obelisk-upgradedeleted

No changes to the content.

migration/4c9372bf9aa6ebed1ea20abf3dbb0075-b641dd9c5359201200e483a784456cc2/obelisk-handoffdeleted

No changes to the content.

migration/4c9372bf9aa6ebed1ea20abf3dbb0075-b641dd9c5359201200e483a784456cc2/obelisk-upgradedeleted

No changes to the content.

migration/4d6197d8166de78f882376102e36300b-4205857df2e234a476ad56f84a33e6ed/obelisk-handoffdeleted

No changes to the content.

migration/4d6197d8166de78f882376102e36300b-4205857df2e234a476ad56f84a33e6ed/obelisk-upgradedeleted

No changes to the content.

migration/4d85ee8cdb0db20a5662b09567a2bbe7-b6425c7661af2116b912a558e9548013/obelisk-handoffdeleted

No changes to the content.

migration/4d85ee8cdb0db20a5662b09567a2bbe7-b6425c7661af2116b912a558e9548013/obelisk-upgradedeleted

No changes to the content.

migration/4da182e21be35feeee484dc85be7a075-14840816db4b5cfd5580ae099022604a/obelisk-handoffdeleted

No changes to the content.

migration/4da182e21be35feeee484dc85be7a075-14840816db4b5cfd5580ae099022604a/obelisk-upgradedeleted

No changes to the content.

migration/4db97ca86399c557e5ee0d04d0838acc-c203adc5fed9bf79f67df43d72a4631a/obelisk-handoffdeleted

No changes to the content.

migration/4db97ca86399c557e5ee0d04d0838acc-c203adc5fed9bf79f67df43d72a4631a/obelisk-upgradedeleted

No changes to the content.

migration/4e3e6e8b9d0f4194842e530438ff686f-b7e30314f9d0e69efdc84c7eb4e3bcc3/obelisk-handoffdeleted

No changes to the content.

migration/4e3e6e8b9d0f4194842e530438ff686f-b7e30314f9d0e69efdc84c7eb4e3bcc3/obelisk-upgradedeleted

No changes to the content.

migration/4e95e2f8ef50420371b71022c644e25d-8df9e256d8e43fa4e22d953024269b5b/obelisk-handoffdeleted

No changes to the content.

migration/4e95e2f8ef50420371b71022c644e25d-8df9e256d8e43fa4e22d953024269b5b/obelisk-upgradedeleted

No changes to the content.

migration/4efbe4a73c260cca09fed7169e82a7ff-315cd79f97dae2f3669551dc03e0fd27/obelisk-handoffdeleted

No changes to the content.

migration/4efbe4a73c260cca09fed7169e82a7ff-315cd79f97dae2f3669551dc03e0fd27/obelisk-upgradedeleted

No changes to the content.

migration/4fe321cf196b9cd25210c35e09e09d8f-56d7fd24c8a996e49bb26dd797819897/obelisk-handoffdeleted

No changes to the content.

migration/4fe321cf196b9cd25210c35e09e09d8f-56d7fd24c8a996e49bb26dd797819897/obelisk-upgradedeleted

No changes to the content.

migration/4ff5bf819ea43a638abbcfa071bbf3ef-975cd8245d06ad09e4fb176cfc9af5e0/obelisk-handoffdeleted

No changes to the content.

migration/4ff5bf819ea43a638abbcfa071bbf3ef-975cd8245d06ad09e4fb176cfc9af5e0/obelisk-upgradedeleted

No changes to the content.

migration/50b85e79010ad50ee275eaeba0df6f8d-e327773e1525eaa1eb2112dff8f41b26/obelisk-handoffdeleted

No changes to the content.

migration/50b85e79010ad50ee275eaeba0df6f8d-e327773e1525eaa1eb2112dff8f41b26/obelisk-upgradedeleted

No changes to the content.

migration/51c7d001730ddd3d76e0c8bb57038773-423088b98df50b986c9197af83c42a25/obelisk-handoffdeleted

No changes to the content.

migration/51c7d001730ddd3d76e0c8bb57038773-423088b98df50b986c9197af83c42a25/obelisk-upgradedeleted

No changes to the content.

migration/51e25cf740f064faa0a29b8e2afcc109-7bc4c944b24621967a6334f522437cc1/obelisk-handoffdeleted

No changes to the content.

migration/51e25cf740f064faa0a29b8e2afcc109-7bc4c944b24621967a6334f522437cc1/obelisk-upgradedeleted

No changes to the content.

migration/51f3d5068259f596b811450f0bf25419-f9716ad47c84e0b7ac7d426e8ad059f3/obelisk-handoffdeleted

No changes to the content.

migration/51f3d5068259f596b811450f0bf25419-f9716ad47c84e0b7ac7d426e8ad059f3/obelisk-upgradedeleted

No changes to the content.

migration/52330622ae996023b3f80a40991521a4-1df871cede0758cabe43971d9091279d/obelisk-handoffdeleted

No changes to the content.

migration/52330622ae996023b3f80a40991521a4-1df871cede0758cabe43971d9091279d/obelisk-upgradedeleted

No changes to the content.

migration/52df183d0f32d5a1e9ebe276b6d83d37-08dbdf23867a8efa680283ad251d3429/obelisk-handoffdeleted

No changes to the content.

migration/52df183d0f32d5a1e9ebe276b6d83d37-08dbdf23867a8efa680283ad251d3429/obelisk-upgradedeleted

No changes to the content.

migration/53d29061537ddaf7530aef88624ab266-9fe2922674fcee5e840c9f52cf534f88/obelisk-handoffdeleted

No changes to the content.

migration/53d29061537ddaf7530aef88624ab266-9fe2922674fcee5e840c9f52cf534f88/obelisk-upgradedeleted

No changes to the content.

migration/53fdf819333b86dfb485bf16a8f28db2-93fc625d41bae9fcf06b9febeacb686d/obelisk-handoffdeleted

No changes to the content.

migration/53fdf819333b86dfb485bf16a8f28db2-93fc625d41bae9fcf06b9febeacb686d/obelisk-upgradedeleted

No changes to the content.

migration/554c459ff2cced3e1b11241ed403890d-3543ea607791bc2e19419d22918823bd/obelisk-handoffdeleted

No changes to the content.

migration/554c459ff2cced3e1b11241ed403890d-3543ea607791bc2e19419d22918823bd/obelisk-upgradedeleted

No changes to the content.

migration/554c459ff2cced3e1b11241ed403890d-6a18939264224d6ce24c7426249edfea/obelisk-handoffdeleted

No changes to the content.

migration/554c459ff2cced3e1b11241ed403890d-6a18939264224d6ce24c7426249edfea/obelisk-upgradedeleted

No changes to the content.

migration/55cf43fb0d3868040c9efbf2f92d538a-e2706f337218a12a3bdddd18fa3f4cfd/obelisk-handoffdeleted

No changes to the content.

migration/55cf43fb0d3868040c9efbf2f92d538a-e2706f337218a12a3bdddd18fa3f4cfd/obelisk-upgradedeleted

No changes to the content.

migration/55d9c5eb3b86c9cb27966f849b2d32cf-0e4d0f0f0af0925474b0d772be2b145f/obelisk-handoffdeleted

No changes to the content.

migration/55d9c5eb3b86c9cb27966f849b2d32cf-0e4d0f0f0af0925474b0d772be2b145f/obelisk-upgradedeleted

No changes to the content.

migration/5631293b75143d170b8fca5579e15fee-0abd9d31c77be8c9a9e83bf1f73276f6/obelisk-handoffdeleted

No changes to the content.

migration/5631293b75143d170b8fca5579e15fee-0abd9d31c77be8c9a9e83bf1f73276f6/obelisk-upgradedeleted

No changes to the content.

migration/569227e5e7754c1890022850fd552292-ff1105290f89350bc9deb6eb907e0a53/obelisk-handoffdeleted

No changes to the content.

migration/569227e5e7754c1890022850fd552292-ff1105290f89350bc9deb6eb907e0a53/obelisk-upgradedeleted

No changes to the content.

migration/56d7fd24c8a996e49bb26dd797819897-61f734d4c59e46f03e92d2b86299c7c9/obelisk-handoffdeleted

No changes to the content.

migration/56d7fd24c8a996e49bb26dd797819897-61f734d4c59e46f03e92d2b86299c7c9/obelisk-upgradedeleted

No changes to the content.

migration/5734398c41e4eb5bb58d933ed2e12041-fb374b0721716a1e849e64daf6da73c4/obelisk-handoffdeleted

No changes to the content.

migration/5734398c41e4eb5bb58d933ed2e12041-fb374b0721716a1e849e64daf6da73c4/obelisk-upgradedeleted

No changes to the content.

migration/58391ba73c13d922e8a12116b28caad2-215b6810b09f219a5cb3842aacc88432/obelisk-handoffdeleted

No changes to the content.

migration/58391ba73c13d922e8a12116b28caad2-215b6810b09f219a5cb3842aacc88432/obelisk-upgradedeleted

No changes to the content.

migration/583ec22b9af66e8f629ee404307eb2dc-6c7f4af3693c31e1a2c6a2c3f189ddf5/obelisk-handoffdeleted

No changes to the content.

migration/583ec22b9af66e8f629ee404307eb2dc-6c7f4af3693c31e1a2c6a2c3f189ddf5/obelisk-upgradedeleted

No changes to the content.

migration/58479e482d3828ce44f2c8371ed9135a-174fa1072ee767be39b7b01aecea5714/obelisk-handoffdeleted

No changes to the content.

migration/58479e482d3828ce44f2c8371ed9135a-174fa1072ee767be39b7b01aecea5714/obelisk-upgradedeleted

No changes to the content.

migration/589eb89cdb09655c5edde4cd2a4deb80-c5a306045ad998f906f80748fe18487f/obelisk-handoffdeleted

No changes to the content.

migration/589eb89cdb09655c5edde4cd2a4deb80-c5a306045ad998f906f80748fe18487f/obelisk-upgradedeleted

No changes to the content.

migration/58f9d23d2cede2081dc6f6cfa2283f60-41e3ba178b727517aa1cedc8815abe86/obelisk-handoffdeleted

No changes to the content.

migration/58f9d23d2cede2081dc6f6cfa2283f60-41e3ba178b727517aa1cedc8815abe86/obelisk-upgradedeleted

No changes to the content.

migration/59742705e53838ae13066a2239a72040-95955d1dd0981ebb538ee941cde1f963/obelisk-handoffdeleted

No changes to the content.

migration/59742705e53838ae13066a2239a72040-95955d1dd0981ebb538ee941cde1f963/obelisk-upgradedeleted

No changes to the content.

migration/59e4a192c611a2a9f6736afde9fe1a0e-8143888349912db9780231c370ea2060/obelisk-handoffdeleted

No changes to the content.

migration/59e4a192c611a2a9f6736afde9fe1a0e-8143888349912db9780231c370ea2060/obelisk-upgradedeleted

No changes to the content.

migration/5a98cdb6c195e88beac878a3f311c5b5-66d79b4c393877a72aec18f227049207/obelisk-handoffdeleted

No changes to the content.

migration/5a98cdb6c195e88beac878a3f311c5b5-66d79b4c393877a72aec18f227049207/obelisk-upgradedeleted

No changes to the content.

migration/5b252c24612c2ba868580add9d9c19e3-6f104c322bbaff565981739406290402/obelisk-handoffdeleted

No changes to the content.

migration/5b252c24612c2ba868580add9d9c19e3-6f104c322bbaff565981739406290402/obelisk-upgradedeleted

No changes to the content.

migration/5b6770965bbef440db49b0703cd243a3-11f38b38c2d38004bb8a9dbfe2ef3e4a/obelisk-handoffdeleted

No changes to the content.

migration/5b6770965bbef440db49b0703cd243a3-11f38b38c2d38004bb8a9dbfe2ef3e4a/obelisk-upgradedeleted

No changes to the content.

migration/5cb98d0250bf5224b94e544a5140a54c-fa18f7522903a21b615dbee24c26bfbe/obelisk-handoffdeleted

No changes to the content.

migration/5cb98d0250bf5224b94e544a5140a54c-fa18f7522903a21b615dbee24c26bfbe/obelisk-upgradedeleted

No changes to the content.

migration/5d90abd974b4ec53091a8cb3fc2258ce-d40e0e3051a76c4c198cc11c2e8e4b7c/obelisk-handoffdeleted

No changes to the content.

migration/5d90abd974b4ec53091a8cb3fc2258ce-d40e0e3051a76c4c198cc11c2e8e4b7c/obelisk-upgradedeleted

No changes to the content.

migration/5f0d3f7480d67df7deebdb880726b356-4ab915b764f38a1b0b4ae6f619f5c3fa/obelisk-handoffdeleted

No changes to the content.

migration/5f0d3f7480d67df7deebdb880726b356-4ab915b764f38a1b0b4ae6f619f5c3fa/obelisk-upgradedeleted

No changes to the content.

migration/5f307639ccf6a64309166bfe58037397-702c65f35bc47641d60580d636ede330/obelisk-handoffdeleted

No changes to the content.

migration/5f307639ccf6a64309166bfe58037397-702c65f35bc47641d60580d636ede330/obelisk-upgradedeleted

No changes to the content.

migration/5f6fe243beb9fcc0c4117536022fc14c-f41b690c74938e347cf042cee2d4fc72/obelisk-handoffdeleted

No changes to the content.

migration/5f6fe243beb9fcc0c4117536022fc14c-f41b690c74938e347cf042cee2d4fc72/obelisk-upgradedeleted

No changes to the content.

migration/6095bdaccd933d319c84cde7983e2d10-477a0bb12b48357d1e2b415c91d904e3/obelisk-handoffdeleted

No changes to the content.

migration/6095bdaccd933d319c84cde7983e2d10-477a0bb12b48357d1e2b415c91d904e3/obelisk-upgradedeleted

No changes to the content.

migration/610dcf99f7eb8c8b591ff3f5f1722938-131e1d5cc8163ce9a174a8782be23fe7/obelisk-handoffdeleted

No changes to the content.

migration/610dcf99f7eb8c8b591ff3f5f1722938-131e1d5cc8163ce9a174a8782be23fe7/obelisk-upgradedeleted

No changes to the content.

migration/61f734d4c59e46f03e92d2b86299c7c9-02d0f8b5c7472e6f8a99ec2cfcb59807/obelisk-handoffdeleted

No changes to the content.

migration/61f734d4c59e46f03e92d2b86299c7c9-02d0f8b5c7472e6f8a99ec2cfcb59807/obelisk-upgradedeleted

No changes to the content.

migration/63422a9bade5c703461b600e03e227f0-01ddc6354698efa1ae5822da3be562dc/obelisk-handoffdeleted

No changes to the content.

migration/63422a9bade5c703461b600e03e227f0-01ddc6354698efa1ae5822da3be562dc/obelisk-upgradedeleted

No changes to the content.

migration/63ff9426130baa080f37400a86c55fdd-569227e5e7754c1890022850fd552292/obelisk-handoffdeleted

No changes to the content.

migration/63ff9426130baa080f37400a86c55fdd-569227e5e7754c1890022850fd552292/obelisk-upgradedeleted

No changes to the content.

migration/64ee9e40f4943e0122398e48019f5616-cd38e239c47fb92fabd867b7f86fc99a/obelisk-handoffdeleted

No changes to the content.

migration/64ee9e40f4943e0122398e48019f5616-cd38e239c47fb92fabd867b7f86fc99a/obelisk-upgradedeleted

No changes to the content.

migration/65071e255719af6389857646bc087d37-02fb88dab35884e09deef1721c1cfc13/obelisk-handoffdeleted

No changes to the content.

migration/65071e255719af6389857646bc087d37-02fb88dab35884e09deef1721c1cfc13/obelisk-upgradedeleted

No changes to the content.

migration/6558f8bda2aa17d76c509dde0a3dea56-2ccf977797628dc3b1c002927fedc7a8/obelisk-handoffdeleted

No changes to the content.

migration/6558f8bda2aa17d76c509dde0a3dea56-2ccf977797628dc3b1c002927fedc7a8/obelisk-upgradedeleted

No changes to the content.

migration/6566f0555737425bae9106d1a4a0a2dd-1f7fb90cb1e558f5285b2d19a25a1078/obelisk-handoffdeleted

No changes to the content.

migration/6566f0555737425bae9106d1a4a0a2dd-1f7fb90cb1e558f5285b2d19a25a1078/obelisk-upgradedeleted

No changes to the content.

migration/6620e6dc5622593e5f671127af9ade05-4ff5bf819ea43a638abbcfa071bbf3ef/obelisk-handoffdeleted

No changes to the content.

migration/6620e6dc5622593e5f671127af9ade05-4ff5bf819ea43a638abbcfa071bbf3ef/obelisk-upgradedeleted

No changes to the content.

migration/662eb30d6e4612f130edc3f6d37d92a2-94dd4eb45a4e7eb945027d5fd8eb4fa6/obelisk-handoffdeleted

No changes to the content.

migration/662eb30d6e4612f130edc3f6d37d92a2-94dd4eb45a4e7eb945027d5fd8eb4fa6/obelisk-upgradedeleted

No changes to the content.

migration/66a9b6b9e9bc4a5b0cfa78127479b231-88765caf54c2bf9f23ea4d05816a9f65/obelisk-handoffdeleted

No changes to the content.

migration/66a9b6b9e9bc4a5b0cfa78127479b231-88765caf54c2bf9f23ea4d05816a9f65/obelisk-upgradedeleted

No changes to the content.

migration/66d79b4c393877a72aec18f227049207-04dd95ecb889ac1b0a616ddfeec781c4/obelisk-handoffdeleted

No changes to the content.

migration/66d79b4c393877a72aec18f227049207-04dd95ecb889ac1b0a616ddfeec781c4/obelisk-upgradedeleted

No changes to the content.

migration/66f7a274206ad9f6d3c5701e4bcffc9d-2e7cdc2bea08bb2358219ddefef372e0/obelisk-handoffdeleted

No changes to the content.

migration/66f7a274206ad9f6d3c5701e4bcffc9d-2e7cdc2bea08bb2358219ddefef372e0/obelisk-upgradedeleted

No changes to the content.

migration/6708d14c71c475ac494808e75660a385-6095bdaccd933d319c84cde7983e2d10/obelisk-handoffdeleted

No changes to the content.

migration/6708d14c71c475ac494808e75660a385-6095bdaccd933d319c84cde7983e2d10/obelisk-upgradedeleted

No changes to the content.

migration/67173f110f2c54d135e6943b65118303-17089ea0edc0cf4b6f616936f8a06174/obelisk-handoffdeleted

No changes to the content.

migration/67173f110f2c54d135e6943b65118303-17089ea0edc0cf4b6f616936f8a06174/obelisk-upgradedeleted

No changes to the content.

migration/67bfa5b784a35e66875fb74ad84a38c0-f3ec62d09836804e39fad9d814137845/obelisk-handoffdeleted

No changes to the content.

migration/67bfa5b784a35e66875fb74ad84a38c0-f3ec62d09836804e39fad9d814137845/obelisk-upgradedeleted

No changes to the content.

migration/68cca18f813a16eb0cc2c3ed7fa08044-ee3dccc89ea6fdaaf9c1146b92861e90/obelisk-handoffdeleted

No changes to the content.

migration/68cca18f813a16eb0cc2c3ed7fa08044-ee3dccc89ea6fdaaf9c1146b92861e90/obelisk-upgradedeleted

No changes to the content.

migration/69537089a0e97845ffe05c73c3cc1536-e92786eaf56c32fd6b452c4a841d6317/obelisk-handoffdeleted

No changes to the content.

migration/69537089a0e97845ffe05c73c3cc1536-e92786eaf56c32fd6b452c4a841d6317/obelisk-upgradedeleted

No changes to the content.

migration/69cd775958e25e3b2cff7e4897f2a9bb-fca48edfdaa31b036176b97b04384682/obelisk-handoffdeleted

No changes to the content.

migration/69cd775958e25e3b2cff7e4897f2a9bb-fca48edfdaa31b036176b97b04384682/obelisk-upgradedeleted

No changes to the content.

migration/69fafe6ab155ff215b6d9d330f700ba1-6558f8bda2aa17d76c509dde0a3dea56/obelisk-handoffdeleted

No changes to the content.

migration/69fafe6ab155ff215b6d9d330f700ba1-6558f8bda2aa17d76c509dde0a3dea56/obelisk-upgradedeleted

No changes to the content.

migration/6a18939264224d6ce24c7426249edfea-e66afc8befac4d76b5780a960f768c31/obelisk-handoffdeleted

No changes to the content.

migration/6a18939264224d6ce24c7426249edfea-e66afc8befac4d76b5780a960f768c31/obelisk-upgradedeleted−15
@@ -1,15 +0,0 @@
1−# ob deploy: HTTPs support
2−
3−Obelisk deployments now support HTTPs. You must upgrade the deployment repo
4−associated with the obelisk project as follows:
5−
6−```
7−cd /your/project's/deployment/repo
8−echo True > enable_https
9−echo admin@yoursite.com > admin_email
10−echo https://yoursite.com/ > config/common/route
11−git add ... && git commit ...
12−ob deploy push
13−```
14−
15−If you do not wish to enable HTTPs, write `False` to `enable_https` instead.
migration/6c7f4af3693c31e1a2c6a2c3f189ddf5-388d7d29a65c1713e07a654e91eb9caf/obelisk-handoffdeleted

No changes to the content.

migration/6c7f4af3693c31e1a2c6a2c3f189ddf5-388d7d29a65c1713e07a654e91eb9caf/obelisk-upgradedeleted

No changes to the content.

migration/6da2e5b02ab780d12527640722d2b511-ca88f98cf9fb63d2feaef7fc19b30eca/obelisk-handoffdeleted

No changes to the content.

migration/6da2e5b02ab780d12527640722d2b511-ca88f98cf9fb63d2feaef7fc19b30eca/obelisk-upgradedeleted

No changes to the content.

migration/6dc299cb41f8977785a5d676cbcd32d7-237aeb7eee0ffed230234ee04e49569f/obelisk-handoffdeleted

No changes to the content.

migration/6dc299cb41f8977785a5d676cbcd32d7-237aeb7eee0ffed230234ee04e49569f/obelisk-upgradedeleted

No changes to the content.

migration/6f104c322bbaff565981739406290402-f98b82f5d142ce83733a3f18bdacb138/obelisk-handoffdeleted

No changes to the content.

migration/6f104c322bbaff565981739406290402-f98b82f5d142ce83733a3f18bdacb138/obelisk-upgradedeleted

No changes to the content.

migration/6f3a0f756847ee5aa208a1dc79404779-00c627540326314c7154cc209e8a71e9/obelisk-handoffdeleted

No changes to the content.

migration/6f3a0f756847ee5aa208a1dc79404779-00c627540326314c7154cc209e8a71e9/obelisk-upgradedeleted

No changes to the content.

migration/6fc44f180bb825d5b372444339681135-6dc299cb41f8977785a5d676cbcd32d7/obelisk-handoffdeleted

No changes to the content.

migration/6fc44f180bb825d5b372444339681135-6dc299cb41f8977785a5d676cbcd32d7/obelisk-upgradedeleted

No changes to the content.

migration/702c65f35bc47641d60580d636ede330-9217718d2b3b217dbba72e7091459548/obelisk-handoffdeleted

No changes to the content.

migration/702c65f35bc47641d60580d636ede330-9217718d2b3b217dbba72e7091459548/obelisk-upgradedeleted

No changes to the content.

migration/71a47d4d6856c1956c0d1c9de9af231f-bb9a87fc325204313d89dbfb689dba2f/obelisk-handoffdeleted

No changes to the content.

migration/71a47d4d6856c1956c0d1c9de9af231f-bb9a87fc325204313d89dbfb689dba2f/obelisk-upgradedeleted

No changes to the content.

migration/71c6959cf98e05d356ff798ada6db2b8-55d9c5eb3b86c9cb27966f849b2d32cf/obelisk-handoffdeleted

No changes to the content.

migration/71c6959cf98e05d356ff798ada6db2b8-55d9c5eb3b86c9cb27966f849b2d32cf/obelisk-upgradedeleted

No changes to the content.

migration/71da39c91abb23488021a1e9142507d5-16b24e1a12b93ea83d7656a09d5e3338/obelisk-handoffdeleted

No changes to the content.

migration/71da39c91abb23488021a1e9142507d5-16b24e1a12b93ea83d7656a09d5e3338/obelisk-upgradedeleted

No changes to the content.

migration/721a02f3a7549e7d6efeaed087bfacb5-52df183d0f32d5a1e9ebe276b6d83d37/obelisk-handoffdeleted

No changes to the content.

migration/721a02f3a7549e7d6efeaed087bfacb5-52df183d0f32d5a1e9ebe276b6d83d37/obelisk-upgradedeleted

No changes to the content.

migration/729aaf942e685bb37fdbd5e97293bbcb-7b2b9cefa7dd57d51b587c3501a1b9ef/obelisk-handoffdeleted

No changes to the content.

migration/729aaf942e685bb37fdbd5e97293bbcb-7b2b9cefa7dd57d51b587c3501a1b9ef/obelisk-upgradedeleted

No changes to the content.

migration/73bcf3ed6593d074bd097cd43f5145d1-375acf7f2a3b3c487da2a6b30735d74d/obelisk-handoffdeleted

No changes to the content.

migration/73bcf3ed6593d074bd097cd43f5145d1-375acf7f2a3b3c487da2a6b30735d74d/obelisk-upgradedeleted

No changes to the content.

migration/73e2573d9074884d7ae83106d55ad229-729aaf942e685bb37fdbd5e97293bbcb/obelisk-handoffdeleted

No changes to the content.

migration/73e2573d9074884d7ae83106d55ad229-729aaf942e685bb37fdbd5e97293bbcb/obelisk-upgradedeleted

No changes to the content.

migration/7447d29f4712c72458c049cdb9380753-e24a771ee59f24e45afc0a27307f2070/obelisk-handoffdeleted

No changes to the content.

migration/7447d29f4712c72458c049cdb9380753-e24a771ee59f24e45afc0a27307f2070/obelisk-upgradedeleted

No changes to the content.

migration/749df832c9305e1c6309a794b0c1b201-2619464637b85cb35376393fe612ddae/obelisk-handoffdeleted

No changes to the content.

migration/749df832c9305e1c6309a794b0c1b201-2619464637b85cb35376393fe612ddae/obelisk-upgradedeleted

No changes to the content.

migration/75c9cd9763d0ed89c17d455f49d66a4f-94372bb14f8afd19bce24f8402c7564c/obelisk-handoffdeleted

No changes to the content.

migration/75c9cd9763d0ed89c17d455f49d66a4f-94372bb14f8afd19bce24f8402c7564c/obelisk-upgradedeleted

No changes to the content.

migration/77a721a8fa97d1f84dd2af622089871b-cb2d040cc16752b1dc89eecf200ea798/obelisk-handoffdeleted

No changes to the content.

migration/77a721a8fa97d1f84dd2af622089871b-cb2d040cc16752b1dc89eecf200ea798/obelisk-upgradedeleted

No changes to the content.

migration/79357758056556793db0472562d62ff9-f15c9c2f894c8cc4fac07e2cdef47180/obelisk-handoffdeleted

No changes to the content.

migration/79357758056556793db0472562d62ff9-f15c9c2f894c8cc4fac07e2cdef47180/obelisk-upgradedeleted

No changes to the content.

migration/7adece557941a7d7ac7c150f77f758be-67173f110f2c54d135e6943b65118303/obelisk-handoffdeleted

No changes to the content.

migration/7adece557941a7d7ac7c150f77f758be-67173f110f2c54d135e6943b65118303/obelisk-upgradedeleted

No changes to the content.

migration/7b2b9cefa7dd57d51b587c3501a1b9ef-1269155fffe21926f3704d5077e04332/obelisk-handoffdeleted

No changes to the content.

migration/7b2b9cefa7dd57d51b587c3501a1b9ef-1269155fffe21926f3704d5077e04332/obelisk-upgradedeleted

No changes to the content.

migration/7b75ffdcd86b5a330d9c325ad5767393-97873167212295a0fdc1219102b6b600/obelisk-handoffdeleted

No changes to the content.

migration/7b75ffdcd86b5a330d9c325ad5767393-97873167212295a0fdc1219102b6b600/obelisk-upgradedeleted

No changes to the content.

migration/7b9c28d09bd962e89b9715500f9e184c-df71cd82e801ca701bf4bc44b80b6d50/obelisk-handoffdeleted

No changes to the content.

migration/7b9c28d09bd962e89b9715500f9e184c-df71cd82e801ca701bf4bc44b80b6d50/obelisk-upgradedeleted

No changes to the content.

migration/7bc4c944b24621967a6334f522437cc1-3e8a6968585d3d60f3b13652a386aec0/obelisk-handoffdeleted

No changes to the content.

migration/7bc4c944b24621967a6334f522437cc1-3e8a6968585d3d60f3b13652a386aec0/obelisk-upgradedeleted

No changes to the content.

migration/7c0ab1210424b615251ef57036d316c3-b8aa42d4f2e5ef7db9ba34ecf6c42079/obelisk-handoffdeleted

No changes to the content.

migration/7c0ab1210424b615251ef57036d316c3-b8aa42d4f2e5ef7db9ba34ecf6c42079/obelisk-upgradedeleted

No changes to the content.

migration/7c98ef4a123c1a580d368d14e54961b7-adad34a1075a2fd51e1a1c06ec9d002d/obelisk-handoffdeleted

No changes to the content.

migration/7c98ef4a123c1a580d368d14e54961b7-adad34a1075a2fd51e1a1c06ec9d002d/obelisk-upgradedeleted

No changes to the content.

migration/7ce32302cfbba8b7567a05144057f8a3-28c5fec3b7b0b14b3625d5c8f60bcf68/obelisk-handoffdeleted

No changes to the content.

migration/7ce32302cfbba8b7567a05144057f8a3-28c5fec3b7b0b14b3625d5c8f60bcf68/obelisk-upgradedeleted

No changes to the content.

migration/7cf814f7404638f1c1be662a24d7cfea-e609d945b642fd9d4ce99931e3699db7/obelisk-handoffdeleted

No changes to the content.

migration/7cf814f7404638f1c1be662a24d7cfea-e609d945b642fd9d4ce99931e3699db7/obelisk-upgradedeleted

No changes to the content.

migration/7dd60550d7d79bd3923d91d67ecb433a-46aed07c1a61476dd245ff8e74c0559f/obelisk-handoffdeleted

No changes to the content.

migration/7dd60550d7d79bd3923d91d67ecb433a-46aed07c1a61476dd245ff8e74c0559f/obelisk-upgradedeleted

No changes to the content.

migration/7f46d84c4d303f30602b920f96acf871-97c7e1ea2c1ddb0ef23d2e4a9279f65c/obelisk-handoffdeleted

No changes to the content.

migration/7f46d84c4d303f30602b920f96acf871-97c7e1ea2c1ddb0ef23d2e4a9279f65c/obelisk-upgradedeleted

No changes to the content.

migration/7fac40a2398039b364746989bb78798b-68cca18f813a16eb0cc2c3ed7fa08044/obelisk-handoffdeleted

No changes to the content.

migration/7fac40a2398039b364746989bb78798b-68cca18f813a16eb0cc2c3ed7fa08044/obelisk-upgradedeleted

No changes to the content.

migration/7fc381538805adac19c54b73ea118601-982c57eada4652019d0b0cf6ad355d25/obelisk-handoffdeleted

No changes to the content.

migration/7fc381538805adac19c54b73ea118601-982c57eada4652019d0b0cf6ad355d25/obelisk-upgradedeleted

No changes to the content.

migration/80cb6b08443d55bb512e4a35b4768b72-59742705e53838ae13066a2239a72040/obelisk-handoffdeleted

No changes to the content.

migration/80cb6b08443d55bb512e4a35b4768b72-59742705e53838ae13066a2239a72040/obelisk-upgradedeleted

No changes to the content.

migration/81223455459db28cdbc990c3d4e6eedd-71da39c91abb23488021a1e9142507d5/obelisk-handoffdeleted

No changes to the content.

migration/81223455459db28cdbc990c3d4e6eedd-71da39c91abb23488021a1e9142507d5/obelisk-upgradedeleted

No changes to the content.

migration/8143888349912db9780231c370ea2060-beaa30317dadbef830531237279cbca4/obelisk-handoffdeleted

No changes to the content.

migration/8143888349912db9780231c370ea2060-beaa30317dadbef830531237279cbca4/obelisk-upgradedeleted

No changes to the content.

migration/81f3dbeef0d78bfb523cd2ac113b8ad8-4ace4414d71235a291f7148f80a0b0f5/obelisk-handoffdeleted

No changes to the content.

migration/81f3dbeef0d78bfb523cd2ac113b8ad8-4ace4414d71235a291f7148f80a0b0f5/obelisk-upgradedeleted

No changes to the content.

migration/84f4d5c5491abb855d8dbe3acf3bc8e6-01fb7610e4184ad1b491267fcb0c7f43/obelisk-handoffdeleted

No changes to the content.

migration/84f4d5c5491abb855d8dbe3acf3bc8e6-01fb7610e4184ad1b491267fcb0c7f43/obelisk-upgradedeleted

No changes to the content.

migration/85c2c4fb8472d50eaa97aed0bdc9b142-3e253c6beb567ba8f4c8086a76b70645/obelisk-handoffdeleted

No changes to the content.

migration/85c2c4fb8472d50eaa97aed0bdc9b142-3e253c6beb567ba8f4c8086a76b70645/obelisk-upgradedeleted

No changes to the content.

migration/8746b8f08b75b2bb7c22d8f17f22d72d-e3b3014d7e0dc983fe118d32546654e5/obelisk-handoffdeleted

No changes to the content.

migration/8746b8f08b75b2bb7c22d8f17f22d72d-e3b3014d7e0dc983fe118d32546654e5/obelisk-upgradedeleted

No changes to the content.

migration/88046de6fbbdad3f6a8a5d311948ff9b-4a037879b8a542f1590cbb87b0242331/obelisk-handoffdeleted

No changes to the content.

migration/88046de6fbbdad3f6a8a5d311948ff9b-4a037879b8a542f1590cbb87b0242331/obelisk-upgradedeleted

No changes to the content.

migration/88439725720c7ba784750cda91157dfd-69cd775958e25e3b2cff7e4897f2a9bb/obelisk-handoffdeleted

No changes to the content.

migration/88439725720c7ba784750cda91157dfd-69cd775958e25e3b2cff7e4897f2a9bb/obelisk-upgradedeleted

No changes to the content.

migration/88765caf54c2bf9f23ea4d05816a9f65-52330622ae996023b3f80a40991521a4/obelisk-handoffdeleted

No changes to the content.

migration/88765caf54c2bf9f23ea4d05816a9f65-52330622ae996023b3f80a40991521a4/obelisk-upgradedeleted

No changes to the content.

migration/8911be694899014078c8e79fc858be45-33da5c0e6705843afa6e39e65bfa0564/obelisk-handoffdeleted

No changes to the content.

migration/8911be694899014078c8e79fc858be45-33da5c0e6705843afa6e39e65bfa0564/obelisk-upgradedeleted

No changes to the content.

migration/8a64ec5f2ee43d69607499f085560857-cba28ee4b736cf8ed43cb342ccaef12e/obelisk-handoffdeleted

No changes to the content.

migration/8a64ec5f2ee43d69607499f085560857-cba28ee4b736cf8ed43cb342ccaef12e/obelisk-upgradedeleted

No changes to the content.

migration/8adb921f4dbb9d363bf6647d304e02fe-bb2f504aa4f6f1ab8ed75697dc773efb/obelisk-handoffdeleted

No changes to the content.

migration/8adb921f4dbb9d363bf6647d304e02fe-bb2f504aa4f6f1ab8ed75697dc773efb/obelisk-upgradedeleted

No changes to the content.

migration/8b098f49e1fd1aa10ca22b9dc312644e-0ec6f67d94d3913cf3243d813238ec39/obelisk-handoffdeleted

No changes to the content.

migration/8b098f49e1fd1aa10ca22b9dc312644e-0ec6f67d94d3913cf3243d813238ec39/obelisk-upgradedeleted

No changes to the content.

migration/8c7718f94e2676c957fe844b7dc2637c-96c3d49b08a9d2cfb059197c60f49c05/obelisk-handoffdeleted

No changes to the content.

migration/8c7718f94e2676c957fe844b7dc2637c-96c3d49b08a9d2cfb059197c60f49c05/obelisk-upgradedeleted

No changes to the content.

migration/8c9599be2461288eee7e78d7a34643d8-053c0b2f84a7a2eadeb5c3f9575ffa0d/obelisk-handoffdeleted

No changes to the content.

migration/8c9599be2461288eee7e78d7a34643d8-053c0b2f84a7a2eadeb5c3f9575ffa0d/obelisk-upgradedeleted

No changes to the content.

migration/8d5dba70e93ae7e784ea238281842408-c93529e579e64263fd91663216fd3fe7/obelisk-handoffdeleted

No changes to the content.

migration/8d5dba70e93ae7e784ea238281842408-c93529e579e64263fd91663216fd3fe7/obelisk-upgradedeleted

No changes to the content.

migration/8dcf46725e839f4a5dcb7a9f0235e01b-0da1150f0e9fe57d1fafbb6cabe24fa1/obelisk-handoffdeleted

No changes to the content.

migration/8dcf46725e839f4a5dcb7a9f0235e01b-0da1150f0e9fe57d1fafbb6cabe24fa1/obelisk-upgradedeleted

No changes to the content.

migration/8df9e256d8e43fa4e22d953024269b5b-9d86cedf551a6ee24c5ae6779021b925/obelisk-handoffdeleted

No changes to the content.

migration/8df9e256d8e43fa4e22d953024269b5b-9d86cedf551a6ee24c5ae6779021b925/obelisk-upgradedeleted

No changes to the content.

migration/8e01c7fee83aa74229a77772d8c928f3-8911be694899014078c8e79fc858be45/obelisk-handoffdeleted

No changes to the content.

migration/8e01c7fee83aa74229a77772d8c928f3-8911be694899014078c8e79fc858be45/obelisk-upgradedeleted

No changes to the content.

migration/8e1e426afe242ea3079f160bccd94cf0-610dcf99f7eb8c8b591ff3f5f1722938/obelisk-handoffdeleted

No changes to the content.

migration/8e1e426afe242ea3079f160bccd94cf0-610dcf99f7eb8c8b591ff3f5f1722938/obelisk-upgradedeleted

No changes to the content.

migration/8fca2c4d6478ed8628925852b2af45bf-03b845f308e73a1567eb843dfca182d2/obelisk-handoffdeleted

No changes to the content.

migration/8fca2c4d6478ed8628925852b2af45bf-03b845f308e73a1567eb843dfca182d2/obelisk-upgradedeleted

No changes to the content.

migration/90489c1a9f7edd46a070d6474dceac86-7fac40a2398039b364746989bb78798b/obelisk-handoffdeleted

No changes to the content.

migration/90489c1a9f7edd46a070d6474dceac86-7fac40a2398039b364746989bb78798b/obelisk-upgradedeleted

No changes to the content.

migration/909b6b2066cbdc991e6c16455f13637c-1e36dc8817e2784df36d643b7499092d/obelisk-handoffdeleted

No changes to the content.

migration/909b6b2066cbdc991e6c16455f13637c-1e36dc8817e2784df36d643b7499092d/obelisk-upgradedeleted

No changes to the content.

migration/90b4e20464e08ade5f215f2a4ea28cc6-b7630e5f30252987bf899c74de3953ad/obelisk-handoffdeleted

No changes to the content.

migration/90b4e20464e08ade5f215f2a4ea28cc6-b7630e5f30252987bf899c74de3953ad/obelisk-upgradedeleted

No changes to the content.

migration/9217718d2b3b217dbba72e7091459548-88046de6fbbdad3f6a8a5d311948ff9b/obelisk-handoffdeleted

No changes to the content.

migration/9217718d2b3b217dbba72e7091459548-88046de6fbbdad3f6a8a5d311948ff9b/obelisk-upgradedeleted

No changes to the content.

migration/9223532a537f698ef36f4dce6e922a6b-d327ceb69d24e40dc11792840454cff9/obelisk-handoffdeleted

No changes to the content.

migration/9223532a537f698ef36f4dce6e922a6b-d327ceb69d24e40dc11792840454cff9/obelisk-upgradedeleted

No changes to the content.

migration/92ab733e8991f12cc12148f8d4e1b35d-e4b89dd259f3831bc60b56147b3586a6/obelisk-handoffdeleted

No changes to the content.

migration/92ab733e8991f12cc12148f8d4e1b35d-e4b89dd259f3831bc60b56147b3586a6/obelisk-upgradedeleted

No changes to the content.

migration/930e9213e072e87c207f93461bd3c96c-7f46d84c4d303f30602b920f96acf871/obelisk-handoffdeleted

No changes to the content.

migration/930e9213e072e87c207f93461bd3c96c-7f46d84c4d303f30602b920f96acf871/obelisk-upgradedeleted

No changes to the content.

migration/93f164bbd887f688fd49bb80afffccd6-f8eee9431c8b7a767d96da0a8cfae95d/obelisk-handoffdeleted

No changes to the content.

migration/93f164bbd887f688fd49bb80afffccd6-f8eee9431c8b7a767d96da0a8cfae95d/obelisk-upgradedeleted

No changes to the content.

migration/93fc625d41bae9fcf06b9febeacb686d-662eb30d6e4612f130edc3f6d37d92a2/obelisk-handoffdeleted

No changes to the content.

migration/93fc625d41bae9fcf06b9febeacb686d-662eb30d6e4612f130edc3f6d37d92a2/obelisk-upgradedeleted

No changes to the content.

migration/94252585266fa745a91733888e2f50b7-d207ab99328b8ece5fb27fa1f4dbf9f6/obelisk-handoffdeleted

No changes to the content.

migration/94252585266fa745a91733888e2f50b7-d207ab99328b8ece5fb27fa1f4dbf9f6/obelisk-upgradedeleted

No changes to the content.

migration/94372bb14f8afd19bce24f8402c7564c-7dd60550d7d79bd3923d91d67ecb433a/obelisk-handoffdeleted

No changes to the content.

migration/94372bb14f8afd19bce24f8402c7564c-7dd60550d7d79bd3923d91d67ecb433a/obelisk-upgradedeleted

No changes to the content.

migration/947784563e3a27cf6486bed9a3c52f15-25615a274650370633e8083ed19fbdd0/obelisk-handoffdeleted

No changes to the content.

migration/947784563e3a27cf6486bed9a3c52f15-25615a274650370633e8083ed19fbdd0/obelisk-upgradedeleted

No changes to the content.

migration/94dd4eb45a4e7eb945027d5fd8eb4fa6-e22c51145e08d4a089003460ae80a7f9/obelisk-handoffdeleted

No changes to the content.

migration/94dd4eb45a4e7eb945027d5fd8eb4fa6-e22c51145e08d4a089003460ae80a7f9/obelisk-upgradedeleted

No changes to the content.

migration/95955d1dd0981ebb538ee941cde1f963-07900e6c41ab9a78917f66fcf7e0d9b8/obelisk-handoffdeleted

No changes to the content.

migration/95955d1dd0981ebb538ee941cde1f963-07900e6c41ab9a78917f66fcf7e0d9b8/obelisk-upgradedeleted

No changes to the content.

migration/959ae2925bcd2b5beff631a8e7aeaf00-071f5b3326b8886de3eddc927b80eb10/obelisk-handoffdeleted

No changes to the content.

migration/959ae2925bcd2b5beff631a8e7aeaf00-071f5b3326b8886de3eddc927b80eb10/obelisk-upgradedeleted

No changes to the content.

migration/962e2bd1ae8d0c233f8da89ecebffe50-d6c090699acd25fc60213ff4bd9eebcf/obelisk-handoffdeleted

No changes to the content.

migration/962e2bd1ae8d0c233f8da89ecebffe50-d6c090699acd25fc60213ff4bd9eebcf/obelisk-upgradedeleted

No changes to the content.

migration/96c3d49b08a9d2cfb059197c60f49c05-6da2e5b02ab780d12527640722d2b511/obelisk-handoffdeleted

No changes to the content.

migration/96c3d49b08a9d2cfb059197c60f49c05-6da2e5b02ab780d12527640722d2b511/obelisk-upgradedeleted

No changes to the content.

migration/9705509619667aacf799e91927c16dc8-2773d4a82ca59b48faf036755e163a5f/obelisk-handoffdeleted

No changes to the content.

migration/9705509619667aacf799e91927c16dc8-2773d4a82ca59b48faf036755e163a5f/obelisk-upgradedeleted

No changes to the content.

migration/9715967793be68dfd8c9a7d631f8d589-d532356dfb65a4c8a39452d2ebca2516/obelisk-handoffdeleted

No changes to the content.

migration/9715967793be68dfd8c9a7d631f8d589-d532356dfb65a4c8a39452d2ebca2516/obelisk-upgradedeleted

No changes to the content.

migration/975cd8245d06ad09e4fb176cfc9af5e0-3f23549fba6f8e67ba36b4405e8680b3/obelisk-handoffdeleted

No changes to the content.

migration/975cd8245d06ad09e4fb176cfc9af5e0-3f23549fba6f8e67ba36b4405e8680b3/obelisk-upgradedeleted

No changes to the content.

migration/97873167212295a0fdc1219102b6b600-88439725720c7ba784750cda91157dfd/obelisk-handoffdeleted

No changes to the content.

migration/97873167212295a0fdc1219102b6b600-88439725720c7ba784750cda91157dfd/obelisk-upgradedeleted

No changes to the content.

migration/97c7e1ea2c1ddb0ef23d2e4a9279f65c-d747c3d0620b2034aca44265dd1c8c86/obelisk-handoffdeleted

No changes to the content.

migration/97c7e1ea2c1ddb0ef23d2e4a9279f65c-d747c3d0620b2034aca44265dd1c8c86/obelisk-upgradedeleted

No changes to the content.

migration/982c57eada4652019d0b0cf6ad355d25-6708d14c71c475ac494808e75660a385/obelisk-handoffdeleted

No changes to the content.

migration/982c57eada4652019d0b0cf6ad355d25-6708d14c71c475ac494808e75660a385/obelisk-upgradedeleted

No changes to the content.

migration/98629a336dcd5fa3524a09f8ea6ad636-8c9599be2461288eee7e78d7a34643d8/obelisk-handoffdeleted

No changes to the content.

migration/98629a336dcd5fa3524a09f8ea6ad636-8c9599be2461288eee7e78d7a34643d8/obelisk-upgradedeleted

No changes to the content.

migration/98da197f133bca81e533ab5ffbf4c82d-a0b418c582d5c6ef9e0cd9a19abe046e/obelisk-handoffdeleted

No changes to the content.

migration/98da197f133bca81e533ab5ffbf4c82d-a0b418c582d5c6ef9e0cd9a19abe046e/obelisk-upgradedeleted

No changes to the content.

migration/98f9e0bbd21e36b0f4daa440d11e7177-bab3871bcfbfcb3d2bad4495d44ae4f8/obelisk-handoffdeleted

No changes to the content.

migration/98f9e0bbd21e36b0f4daa440d11e7177-bab3871bcfbfcb3d2bad4495d44ae4f8/obelisk-upgradedeleted

No changes to the content.

migration/99aebbfcac51725464bc59571b7d71b8-34d14d4a444d3bf1487ada6129815df4/obelisk-handoffdeleted

No changes to the content.

migration/99aebbfcac51725464bc59571b7d71b8-34d14d4a444d3bf1487ada6129815df4/obelisk-upgradedeleted

No changes to the content.

migration/9b33a49f0c978e27b752fa457aca97cc-51f3d5068259f596b811450f0bf25419/obelisk-handoffdeleted

No changes to the content.

migration/9b33a49f0c978e27b752fa457aca97cc-51f3d5068259f596b811450f0bf25419/obelisk-upgradedeleted

No changes to the content.

migration/9b9d73736773550dde7d36de2498b029-69537089a0e97845ffe05c73c3cc1536/obelisk-handoffdeleted

No changes to the content.

migration/9b9d73736773550dde7d36de2498b029-69537089a0e97845ffe05c73c3cc1536/obelisk-upgradedeleted

No changes to the content.

migration/9c94cd459a25b5c2de56067c8fdac620-721a02f3a7549e7d6efeaed087bfacb5/obelisk-handoffdeleted

No changes to the content.

migration/9c94cd459a25b5c2de56067c8fdac620-721a02f3a7549e7d6efeaed087bfacb5/obelisk-upgradedeleted

No changes to the content.

migration/9cef2dd1885f16455ff9b6801ec99454-63ff9426130baa080f37400a86c55fdd/obelisk-handoffdeleted

No changes to the content.

migration/9cef2dd1885f16455ff9b6801ec99454-63ff9426130baa080f37400a86c55fdd/obelisk-upgradedeleted

No changes to the content.

migration/9d86cedf551a6ee24c5ae6779021b925-1c9bdb5c544f2e5432f549653a61dabe/obelisk-handoffdeleted

No changes to the content.

migration/9d86cedf551a6ee24c5ae6779021b925-1c9bdb5c544f2e5432f549653a61dabe/obelisk-upgradedeleted

No changes to the content.

migration/9e05cc6b81c6380ba0ac59bad1021cac-ce7f0d15d71d36d4bcf4fbadcdfa1b58/obelisk-handoffdeleted

No changes to the content.

migration/9e05cc6b81c6380ba0ac59bad1021cac-ce7f0d15d71d36d4bcf4fbadcdfa1b58/obelisk-upgradedeleted

No changes to the content.

migration/9e61f37dd79310b71c80ee166aeb4e80-466a19f9cfa2a103467fe6627225d27f/obelisk-handoffdeleted

No changes to the content.

migration/9e61f37dd79310b71c80ee166aeb4e80-466a19f9cfa2a103467fe6627225d27f/obelisk-upgradedeleted

No changes to the content.

migration/9f6c8fd80ab3ff2dcc48bfd211c8b761-24f151a674662ac47845237d7a9f6a4f/obelisk-handoffdeleted

No changes to the content.

migration/9f6c8fd80ab3ff2dcc48bfd211c8b761-24f151a674662ac47845237d7a9f6a4f/obelisk-upgradedeleted

No changes to the content.

migration/9f71fc9d2ed805fecbc8c4a3aae5685b-cb2197d0267b52385ee39bf4adcfe475/obelisk-handoffdeleted

No changes to the content.

migration/9f71fc9d2ed805fecbc8c4a3aae5685b-cb2197d0267b52385ee39bf4adcfe475/obelisk-upgradedeleted

No changes to the content.

migration/9fb504b182cbd8dfb666175b651e0b49-338b92f88c49c7c3a1d8ec231d9f7189/obelisk-handoffdeleted

No changes to the content.

migration/9fb504b182cbd8dfb666175b651e0b49-338b92f88c49c7c3a1d8ec231d9f7189/obelisk-upgradedeleted

No changes to the content.

migration/9fe2922674fcee5e840c9f52cf534f88-ac92878eb85c5283bcc5f3f34cd35aa6/obelisk-handoffdeleted

No changes to the content.

migration/9fe2922674fcee5e840c9f52cf534f88-ac92878eb85c5283bcc5f3f34cd35aa6/obelisk-upgradedeleted

No changes to the content.

migration/a00870cfca85ff8dae5db3a78f5a227d-c2502429502b46133a749f021d188cf0/obelisk-handoffdeleted

No changes to the content.

migration/a00870cfca85ff8dae5db3a78f5a227d-c2502429502b46133a749f021d188cf0/obelisk-upgradedeleted

No changes to the content.

migration/a080b8549e32f21fec11084f4ab1e052-bd7c24fc03bf82e5a990515531a69147/obelisk-handoffdeleted

No changes to the content.

migration/a080b8549e32f21fec11084f4ab1e052-bd7c24fc03bf82e5a990515531a69147/obelisk-upgradedeleted

No changes to the content.

migration/a08aebb6f40fb45d174b229532314ac4-1c1c3f2b4426d5d26377eef08dbccb3c/obelisk-handoffdeleted

No changes to the content.

migration/a08aebb6f40fb45d174b229532314ac4-1c1c3f2b4426d5d26377eef08dbccb3c/obelisk-upgradedeleted

No changes to the content.

migration/a0b418c582d5c6ef9e0cd9a19abe046e-63422a9bade5c703461b600e03e227f0/obelisk-handoffdeleted

No changes to the content.

migration/a0b418c582d5c6ef9e0cd9a19abe046e-63422a9bade5c703461b600e03e227f0/obelisk-upgradedeleted

No changes to the content.

migration/a0f5ac2ff5c6a957e565f898a9fc8bfb-bf3fbc8db3d6fd42a37982dfb5a30b5c/obelisk-handoffdeleted

No changes to the content.

migration/a0f5ac2ff5c6a957e565f898a9fc8bfb-bf3fbc8db3d6fd42a37982dfb5a30b5c/obelisk-upgradedeleted

No changes to the content.

migration/a262678b7d849de5a9732d06199666ae-ebb95c5864d1d1d2f78fbf7cc8235dac/obelisk-handoffdeleted

No changes to the content.

migration/a262678b7d849de5a9732d06199666ae-ebb95c5864d1d1d2f78fbf7cc8235dac/obelisk-upgradedeleted

No changes to the content.

migration/a2665cfd303a4a34a7bfa3b7d0d264bb-aff3f143ddaa4ed3ffad873d6638e277/obelisk-handoffdeleted

No changes to the content.

migration/a2665cfd303a4a34a7bfa3b7d0d264bb-aff3f143ddaa4ed3ffad873d6638e277/obelisk-upgradedeleted

No changes to the content.

migration/a2b33f8dc1f90b8dddce942b174be5b8-00a480749e96ef7e21fbe8f4943152b1/obelisk-handoffdeleted

No changes to the content.

migration/a2b33f8dc1f90b8dddce942b174be5b8-00a480749e96ef7e21fbe8f4943152b1/obelisk-upgradedeleted

No changes to the content.

migration/a2bdbf1985b75442e78e84523c4ced5f-48c027da19d895ba03e7b9120f771291/obelisk-handoffdeleted

No changes to the content.

migration/a2bdbf1985b75442e78e84523c4ced5f-48c027da19d895ba03e7b9120f771291/obelisk-upgradedeleted

No changes to the content.

migration/a34d758508a0a5d08bc10e76482c4d11-8fca2c4d6478ed8628925852b2af45bf/obelisk-handoffdeleted

No changes to the content.

migration/a34d758508a0a5d08bc10e76482c4d11-8fca2c4d6478ed8628925852b2af45bf/obelisk-upgradedeleted

No changes to the content.

migration/a4477746ae1a7024bc3cd0807180d418-fb5110e527cf77c568bcae7d435ee035/obelisk-handoffdeleted

No changes to the content.

migration/a4477746ae1a7024bc3cd0807180d418-fb5110e527cf77c568bcae7d435ee035/obelisk-upgradedeleted

No changes to the content.

migration/a5297d8457aa4c327f35d4697f6cb66f-2f928f9c4a137186f808a231c9e3c141/obelisk-handoffdeleted

No changes to the content.

migration/a5297d8457aa4c327f35d4697f6cb66f-2f928f9c4a137186f808a231c9e3c141/obelisk-upgradedeleted

No changes to the content.

migration/a536d01b9c489f5e00e30abf27427da0-b8a8ffc909e5fc350d9f8a6a90e7b3d9/obelisk-handoffdeleted

No changes to the content.

migration/a536d01b9c489f5e00e30abf27427da0-b8a8ffc909e5fc350d9f8a6a90e7b3d9/obelisk-upgradedeleted

No changes to the content.

migration/a5904e3a899e346fe2fe26314f69c075-e4513b485b6ba8b7f4bd34b12458ff0c/obelisk-handoffdeleted

No changes to the content.

migration/a5904e3a899e346fe2fe26314f69c075-e4513b485b6ba8b7f4bd34b12458ff0c/obelisk-upgradedeleted

No changes to the content.

migration/a5bbc0b9ceab9c3f7ca32a7da8c1f685-3c4b3152f0608d23d07240e2df3ff8da/obelisk-handoffdeleted

No changes to the content.

migration/a5bbc0b9ceab9c3f7ca32a7da8c1f685-3c4b3152f0608d23d07240e2df3ff8da/obelisk-upgradedeleted

No changes to the content.

migration/a5e40d67714a1b2daa06e3fb3293216d-04a5ae41e8fcef5f719cb84d01430382/obelisk-handoffdeleted

No changes to the content.

migration/a5e40d67714a1b2daa06e3fb3293216d-04a5ae41e8fcef5f719cb84d01430382/obelisk-upgradedeleted

No changes to the content.

migration/a632452cf9c5956becd1a40512472b43-d6a3ea5f7eb3c95f5e5ea09fb1330270/obelisk-handoffdeleted

No changes to the content.

migration/a632452cf9c5956becd1a40512472b43-d6a3ea5f7eb3c95f5e5ea09fb1330270/obelisk-upgradedeleted

No changes to the content.

migration/a6633fc9687566aa84c3d5d5e2bff4fd-b5cab336f6244293913433101cd0feff/obelisk-handoffdeleted

No changes to the content.

migration/a6633fc9687566aa84c3d5d5e2bff4fd-b5cab336f6244293913433101cd0feff/obelisk-upgradedeleted

No changes to the content.

migration/a6d50c7e756dfd1e3ae891111b81a1ae-270b3b3f7bc510c692e3253a895f122a/obelisk-handoffdeleted

No changes to the content.

migration/a6d50c7e756dfd1e3ae891111b81a1ae-270b3b3f7bc510c692e3253a895f122a/obelisk-upgradedeleted

No changes to the content.

migration/a7c7b80a875d1863f027c97eb433b884-cbe155a3e856fb7eaad0bd18feb408be/obelisk-handoffdeleted

No changes to the content.

migration/a7c7b80a875d1863f027c97eb433b884-cbe155a3e856fb7eaad0bd18feb408be/obelisk-upgradedeleted

No changes to the content.

migration/a808a04519bbf2874e41028ded9c180c-8e1e426afe242ea3079f160bccd94cf0/obelisk-handoffdeleted

No changes to the content.

migration/a808a04519bbf2874e41028ded9c180c-8e1e426afe242ea3079f160bccd94cf0/obelisk-upgradedeleted

No changes to the content.

migration/a825fbb74e8d050a5ce10ec4c62b83f5-c3298d81428117be58196b80853e3c7b/obelisk-handoffdeleted

No changes to the content.

migration/a825fbb74e8d050a5ce10ec4c62b83f5-c3298d81428117be58196b80853e3c7b/obelisk-upgradedeleted

No changes to the content.

migration/a826f01311fe00ef5cf87568832605d3-9fb504b182cbd8dfb666175b651e0b49/obelisk-handoffdeleted

No changes to the content.

migration/a826f01311fe00ef5cf87568832605d3-9fb504b182cbd8dfb666175b651e0b49/obelisk-upgradedeleted

No changes to the content.

migration/a878ad346b9305ad2ae3fd85410a7ed7-0f78d9d6875933336bbf0c1c8888b73f/obelisk-handoffdeleted

No changes to the content.

migration/a878ad346b9305ad2ae3fd85410a7ed7-0f78d9d6875933336bbf0c1c8888b73f/obelisk-upgradedeleted

No changes to the content.

migration/a8ebe201ab7a7b0211de41b14a95192e-65071e255719af6389857646bc087d37/obelisk-handoffdeleted

No changes to the content.

migration/a8ebe201ab7a7b0211de41b14a95192e-65071e255719af6389857646bc087d37/obelisk-upgradedeleted

No changes to the content.

migration/a96d491705acc139315264fd340d228f-be615dc4d60c9d8710fbd120857c2fa1/obelisk-handoffdeleted

No changes to the content.

migration/a96d491705acc139315264fd340d228f-be615dc4d60c9d8710fbd120857c2fa1/obelisk-upgradedeleted

No changes to the content.

migration/aa8e6712fd46824acdea303068634078-dc95f39fb27634ccbca7318ff2065608/obelisk-handoffdeleted

No changes to the content.

migration/aa8e6712fd46824acdea303068634078-dc95f39fb27634ccbca7318ff2065608/obelisk-upgradedeleted

No changes to the content.

migration/aaf979dd0121603a8b48127e1ea47c7d-4b7a36dce2c1cf94554e12d8a7903269/obelisk-handoffdeleted

No changes to the content.

migration/aaf979dd0121603a8b48127e1ea47c7d-4b7a36dce2c1cf94554e12d8a7903269/obelisk-upgradedeleted

No changes to the content.

migration/abdb013baf130e1bd7e7fd04e535c44c-39df6544d6b035d4c77cc829729f9c19/obelisk-handoffdeleted

No changes to the content.

migration/abdb013baf130e1bd7e7fd04e535c44c-39df6544d6b035d4c77cc829729f9c19/obelisk-upgradedeleted

No changes to the content.

migration/ac5e28caddd6832d0bf1f7445a4a6a28-e01cc01684deaf4c75ad5d65270bf3d5/obelisk-handoffdeleted

No changes to the content.

migration/ac5e28caddd6832d0bf1f7445a4a6a28-e01cc01684deaf4c75ad5d65270bf3d5/obelisk-upgradedeleted

No changes to the content.

migration/ac92878eb85c5283bcc5f3f34cd35aa6-145650b66e83adf5bdb8261593076379/obelisk-handoffdeleted

No changes to the content.

migration/ac92878eb85c5283bcc5f3f34cd35aa6-145650b66e83adf5bdb8261593076379/obelisk-upgradedeleted

No changes to the content.

migration/adad34a1075a2fd51e1a1c06ec9d002d-930e9213e072e87c207f93461bd3c96c/obelisk-handoffdeleted

No changes to the content.

migration/adad34a1075a2fd51e1a1c06ec9d002d-930e9213e072e87c207f93461bd3c96c/obelisk-upgradedeleted

No changes to the content.

migration/ae4328daeb7d2c52c534a687fbd184b6-3e763ebe16cc3a261f5776ab1f1f6d9a/obelisk-handoffdeleted

No changes to the content.

migration/ae4328daeb7d2c52c534a687fbd184b6-3e763ebe16cc3a261f5776ab1f1f6d9a/obelisk-upgradedeleted

No changes to the content.

migration/ae824b83b569b3b23b8e198190371ca0-81f3dbeef0d78bfb523cd2ac113b8ad8/obelisk-handoffdeleted

No changes to the content.

migration/ae824b83b569b3b23b8e198190371ca0-81f3dbeef0d78bfb523cd2ac113b8ad8/obelisk-upgradedeleted

No changes to the content.

migration/ae8862f8b7292690c852111ca5659ce9-ae4328daeb7d2c52c534a687fbd184b6/obelisk-handoffdeleted

No changes to the content.

migration/ae8862f8b7292690c852111ca5659ce9-ae4328daeb7d2c52c534a687fbd184b6/obelisk-upgradedeleted

No changes to the content.

migration/aeafaa5d20bab4439a5d31f29023a839-79357758056556793db0472562d62ff9/obelisk-handoffdeleted

No changes to the content.

migration/aeafaa5d20bab4439a5d31f29023a839-79357758056556793db0472562d62ff9/obelisk-upgradedeleted

No changes to the content.

migration/aef6ac052515a869c7d3061d4ccc69dd-15f3f3f517b38664131b85da0594522f/obelisk-handoffdeleted

No changes to the content.

migration/aef6ac052515a869c7d3061d4ccc69dd-15f3f3f517b38664131b85da0594522f/obelisk-upgradedeleted

No changes to the content.

migration/afbd010add526d309dccee6895e42d0d-6f3a0f756847ee5aa208a1dc79404779/obelisk-handoffdeleted

No changes to the content.

migration/afbd010add526d309dccee6895e42d0d-6f3a0f756847ee5aa208a1dc79404779/obelisk-upgradedeleted

No changes to the content.

migration/aff3f143ddaa4ed3ffad873d6638e277-6fc44f180bb825d5b372444339681135/obelisk-handoffdeleted

No changes to the content.

migration/aff3f143ddaa4ed3ffad873d6638e277-6fc44f180bb825d5b372444339681135/obelisk-upgradedeleted

No changes to the content.

migration/b0c1d039514a686529561f186332c91e-a878ad346b9305ad2ae3fd85410a7ed7/obelisk-handoffdeleted

No changes to the content.

migration/b0c1d039514a686529561f186332c91e-a878ad346b9305ad2ae3fd85410a7ed7/obelisk-upgradedeleted

No changes to the content.

migration/b1692927da5ed59af72fac5be8094fa2-d5ba6f13296205e5bd88ca2756107df0/obelisk-handoffdeleted

No changes to the content.

migration/b1692927da5ed59af72fac5be8094fa2-d5ba6f13296205e5bd88ca2756107df0/obelisk-upgradedeleted

No changes to the content.

migration/b2282679f6f63cec89d921c3dd512d1e-1f09fcf196bfe90ed52f113c38ffbfdb/obelisk-handoffdeleted

No changes to the content.

migration/b2282679f6f63cec89d921c3dd512d1e-1f09fcf196bfe90ed52f113c38ffbfdb/obelisk-upgradedeleted

No changes to the content.

migration/b3b107d406a6a7675cd5b9f52e5f7d8e-0d3b4cfe9b4c72b830780a4c44942176/obelisk-handoffdeleted

No changes to the content.

migration/b3b107d406a6a7675cd5b9f52e5f7d8e-0d3b4cfe9b4c72b830780a4c44942176/obelisk-upgradedeleted

No changes to the content.

migration/b3ff195b0a90ef5900f9cef2ba75f2fe-24e0d027f4160a6478c1356e51f419cf/obelisk-handoffdeleted

No changes to the content.

migration/b3ff195b0a90ef5900f9cef2ba75f2fe-24e0d027f4160a6478c1356e51f419cf/obelisk-upgradedeleted

No changes to the content.

migration/b4f6596f2c16811442d8bb2961fbb721-3c7755e495f20cfac5e4dabe78644c5a/obelisk-handoffdeleted

No changes to the content.

migration/b4f6596f2c16811442d8bb2961fbb721-3c7755e495f20cfac5e4dabe78644c5a/obelisk-upgradedeleted

No changes to the content.

migration/b5cab336f6244293913433101cd0feff-8746b8f08b75b2bb7c22d8f17f22d72d/obelisk-handoffdeleted

No changes to the content.

migration/b5cab336f6244293913433101cd0feff-8746b8f08b75b2bb7c22d8f17f22d72d/obelisk-upgradedeleted

No changes to the content.

migration/b641dd9c5359201200e483a784456cc2-cc4307fc88e3486b1c3f9ce07db95808/obelisk-handoffdeleted

No changes to the content.

migration/b641dd9c5359201200e483a784456cc2-cc4307fc88e3486b1c3f9ce07db95808/obelisk-upgradedeleted

No changes to the content.

migration/b6425c7661af2116b912a558e9548013-4aefa80392582ec03a19f946e752d331/obelisk-handoffdeleted

No changes to the content.

migration/b6425c7661af2116b912a558e9548013-4aefa80392582ec03a19f946e752d331/obelisk-upgradedeleted

No changes to the content.

migration/b68a785fbf27a63334ef1d1fe82b2dac-d6b34eba6ed4f89875a6615fe2c41ec2/obelisk-handoffdeleted

No changes to the content.

migration/b68a785fbf27a63334ef1d1fe82b2dac-d6b34eba6ed4f89875a6615fe2c41ec2/obelisk-upgradedeleted

No changes to the content.

migration/b6ffce85249f30616da76334c7bbec6e-66a9b6b9e9bc4a5b0cfa78127479b231/obelisk-handoffdeleted

No changes to the content.

migration/b6ffce85249f30616da76334c7bbec6e-66a9b6b9e9bc4a5b0cfa78127479b231/obelisk-upgradedeleted

No changes to the content.

migration/b7630e5f30252987bf899c74de3953ad-3f0687592a77c0c66193652e9cd981fd/obelisk-handoffdeleted

No changes to the content.

migration/b7630e5f30252987bf899c74de3953ad-3f0687592a77c0c66193652e9cd981fd/obelisk-upgradedeleted

No changes to the content.

migration/b7e30314f9d0e69efdc84c7eb4e3bcc3-e4051219d89b3c9a8350fe824ad96a82/obelisk-handoffdeleted

No changes to the content.

migration/b7e30314f9d0e69efdc84c7eb4e3bcc3-e4051219d89b3c9a8350fe824ad96a82/obelisk-upgradedeleted

No changes to the content.

migration/b82e9c3fe22feff4bb3a6be49943fd6c-fbb3eb3209281031dc5183d289eb4e75/obelisk-handoffdeleted

No changes to the content.

migration/b82e9c3fe22feff4bb3a6be49943fd6c-fbb3eb3209281031dc5183d289eb4e75/obelisk-upgradedeleted

No changes to the content.

migration/b8a8ffc909e5fc350d9f8a6a90e7b3d9-aef6ac052515a869c7d3061d4ccc69dd/obelisk-handoffdeleted

No changes to the content.

migration/b8a8ffc909e5fc350d9f8a6a90e7b3d9-aef6ac052515a869c7d3061d4ccc69dd/obelisk-upgradedeleted

No changes to the content.

migration/b8aa42d4f2e5ef7db9ba34ecf6c42079-37c2ed0ba2cd54c0ec29eae9043bc4c8/obelisk-handoffdeleted

No changes to the content.

migration/b8aa42d4f2e5ef7db9ba34ecf6c42079-37c2ed0ba2cd54c0ec29eae9043bc4c8/obelisk-upgradedeleted

No changes to the content.

migration/b95c8d049256fb7360ca14b12acd8544-e7b17aa124e17c357cead8081a58f089/obelisk-handoffdeleted

No changes to the content.

migration/b95c8d049256fb7360ca14b12acd8544-e7b17aa124e17c357cead8081a58f089/obelisk-upgradedeleted

No changes to the content.

migration/ba0ccd5ef6110f6c5133d9d6ea6277f0-e78ec85bec14f4784faeef4d8d3e4d0a/obelisk-handoffdeleted

No changes to the content.

migration/ba0ccd5ef6110f6c5133d9d6ea6277f0-e78ec85bec14f4784faeef4d8d3e4d0a/obelisk-upgradedeleted

No changes to the content.

migration/ba4829dc61dcc12bcafd8de5fc8a76dc-2164344be67da5d0e57052c15f30646d/obelisk-handoffdeleted

No changes to the content.

migration/ba4829dc61dcc12bcafd8de5fc8a76dc-2164344be67da5d0e57052c15f30646d/obelisk-upgradedeleted

No changes to the content.

migration/bab3871bcfbfcb3d2bad4495d44ae4f8-9cef2dd1885f16455ff9b6801ec99454/obelisk-handoffdeleted

No changes to the content.

migration/bab3871bcfbfcb3d2bad4495d44ae4f8-9cef2dd1885f16455ff9b6801ec99454/obelisk-upgradedeleted

No changes to the content.

migration/bb2f504aa4f6f1ab8ed75697dc773efb-bcd13da3a7fba8514084c1a9dbeabb31/obelisk-handoffdeleted

No changes to the content.

migration/bb2f504aa4f6f1ab8ed75697dc773efb-bcd13da3a7fba8514084c1a9dbeabb31/obelisk-upgradedeleted

No changes to the content.

migration/bb9a87fc325204313d89dbfb689dba2f-d2d86ce0ca16b143b49374302a9e9e2f/obelisk-handoffdeleted

No changes to the content.

migration/bb9a87fc325204313d89dbfb689dba2f-d2d86ce0ca16b143b49374302a9e9e2f/obelisk-upgradedeleted

No changes to the content.

migration/bc7688ff47218c0e13d02d917b03caa0-2bdd4221307cafa3e98c4d3017cdc912/obelisk-handoffdeleted

No changes to the content.

migration/bc7688ff47218c0e13d02d917b03caa0-2bdd4221307cafa3e98c4d3017cdc912/obelisk-upgradedeleted

No changes to the content.

migration/bcd13da3a7fba8514084c1a9dbeabb31-8dcf46725e839f4a5dcb7a9f0235e01b/obelisk-handoffdeleted

No changes to the content.

migration/bcd13da3a7fba8514084c1a9dbeabb31-8dcf46725e839f4a5dcb7a9f0235e01b/obelisk-upgradedeleted

No changes to the content.

migration/bd6728737dffcc3505d30ada344e2f4b-1cc8d98f6f61441570fdde2d697e6e3c/obelisk-handoffdeleted

No changes to the content.

migration/bd6728737dffcc3505d30ada344e2f4b-1cc8d98f6f61441570fdde2d697e6e3c/obelisk-upgradedeleted

No changes to the content.

migration/bd7c24fc03bf82e5a990515531a69147-a5e40d67714a1b2daa06e3fb3293216d/obelisk-handoffdeleted

No changes to the content.

migration/bd7c24fc03bf82e5a990515531a69147-a5e40d67714a1b2daa06e3fb3293216d/obelisk-upgradedeleted

No changes to the content.

migration/bd8f5fa095c3eb19b87d85247b36f1df-5d90abd974b4ec53091a8cb3fc2258ce/obelisk-handoffdeleted

No changes to the content.

migration/bd8f5fa095c3eb19b87d85247b36f1df-5d90abd974b4ec53091a8cb3fc2258ce/obelisk-upgradedeleted

No changes to the content.

migration/be5a7b436cef0ae35cb074700d5f0d00-7c0ab1210424b615251ef57036d316c3/obelisk-handoffdeleted

No changes to the content.

migration/be5a7b436cef0ae35cb074700d5f0d00-7c0ab1210424b615251ef57036d316c3/obelisk-upgradedeleted

No changes to the content.

migration/be615dc4d60c9d8710fbd120857c2fa1-1e376437f069662df26178e4a7873190/obelisk-handoffdeleted

No changes to the content.

migration/be615dc4d60c9d8710fbd120857c2fa1-1e376437f069662df26178e4a7873190/obelisk-upgradedeleted

No changes to the content.

migration/beaa30317dadbef830531237279cbca4-a0f5ac2ff5c6a957e565f898a9fc8bfb/obelisk-handoffdeleted

No changes to the content.

migration/beaa30317dadbef830531237279cbca4-a0f5ac2ff5c6a957e565f898a9fc8bfb/obelisk-upgradedeleted

No changes to the content.

migration/bf22c91488f01ebf503c1786ee805d0c-64ee9e40f4943e0122398e48019f5616/obelisk-handoffdeleted

No changes to the content.

migration/bf22c91488f01ebf503c1786ee805d0c-64ee9e40f4943e0122398e48019f5616/obelisk-upgradedeleted

No changes to the content.

migration/bf3fbc8db3d6fd42a37982dfb5a30b5c-0c6127453069ad707e34ddfedb67e2f9/obelisk-handoffdeleted

No changes to the content.

migration/bf3fbc8db3d6fd42a37982dfb5a30b5c-0c6127453069ad707e34ddfedb67e2f9/obelisk-upgradedeleted

No changes to the content.

migration/bf81caf2a7d528f86acacc1f5d2ffcfa-a5bbc0b9ceab9c3f7ca32a7da8c1f685/obelisk-handoffdeleted

No changes to the content.

migration/bf81caf2a7d528f86acacc1f5d2ffcfa-a5bbc0b9ceab9c3f7ca32a7da8c1f685/obelisk-upgradedeleted

No changes to the content.

migration/c0811b664036c7996fcfd19fee241a10-a2bdbf1985b75442e78e84523c4ced5f/obelisk-handoffdeleted

No changes to the content.

migration/c0811b664036c7996fcfd19fee241a10-a2bdbf1985b75442e78e84523c4ced5f/obelisk-upgradedeleted

No changes to the content.

migration/c0c1452986b8d4c181bb0c6c83c56a2f-bf22c91488f01ebf503c1786ee805d0c/obelisk-handoffdeleted

No changes to the content.

migration/c0c1452986b8d4c181bb0c6c83c56a2f-bf22c91488f01ebf503c1786ee805d0c/obelisk-upgradedeleted

No changes to the content.

migration/c106f9398d5c203a1a296b85c7411bf9-1c2c93819c07f33ad899e39ec6769c3c/obelisk-handoffdeleted

No changes to the content.

migration/c106f9398d5c203a1a296b85c7411bf9-1c2c93819c07f33ad899e39ec6769c3c/obelisk-upgradedeleted

No changes to the content.

migration/c118e1ee09ec8d9aa3edf04e211ae035-749df832c9305e1c6309a794b0c1b201/obelisk-handoffdeleted

No changes to the content.

migration/c118e1ee09ec8d9aa3edf04e211ae035-749df832c9305e1c6309a794b0c1b201/obelisk-upgradedeleted

No changes to the content.

migration/c203adc5fed9bf79f67df43d72a4631a-e6980e47ba847245dfab61fb4d5b8ce5/obelisk-handoffdeleted

No changes to the content.

migration/c203adc5fed9bf79f67df43d72a4631a-e6980e47ba847245dfab61fb4d5b8ce5/obelisk-upgradedeleted

No changes to the content.

migration/c2502429502b46133a749f021d188cf0-93f164bbd887f688fd49bb80afffccd6/obelisk-handoffdeleted

No changes to the content.

migration/c2502429502b46133a749f021d188cf0-93f164bbd887f688fd49bb80afffccd6/obelisk-upgradedeleted

No changes to the content.

migration/c2d4eeb20f2b319a2d9dc5b6b0762f83-01c0ee6c93a3f9f69e097c41169927ac/obelisk-handoffdeleted

No changes to the content.

migration/c2d4eeb20f2b319a2d9dc5b6b0762f83-01c0ee6c93a3f9f69e097c41169927ac/obelisk-upgradedeleted

No changes to the content.

migration/c2d581d48dd821a94d7906ca8f33b504-81223455459db28cdbc990c3d4e6eedd/obelisk-handoffdeleted

No changes to the content.

migration/c2d581d48dd821a94d7906ca8f33b504-81223455459db28cdbc990c3d4e6eedd/obelisk-upgradedeleted

No changes to the content.

migration/c3298d81428117be58196b80853e3c7b-f68462dc88ed7fc451d1c757c040cfee/obelisk-handoffdeleted

No changes to the content.

migration/c3298d81428117be58196b80853e3c7b-f68462dc88ed7fc451d1c757c040cfee/obelisk-upgradedeleted

No changes to the content.

migration/c3a8b70b1290031feb21880914cb081e-c2d581d48dd821a94d7906ca8f33b504/obelisk-handoffdeleted

No changes to the content.

migration/c3a8b70b1290031feb21880914cb081e-c2d581d48dd821a94d7906ca8f33b504/obelisk-upgradedeleted

No changes to the content.

migration/c56de2f95c90def16704f62639246bbc-77a721a8fa97d1f84dd2af622089871b/obelisk-handoffdeleted

No changes to the content.

migration/c56de2f95c90def16704f62639246bbc-77a721a8fa97d1f84dd2af622089871b/obelisk-upgradedeleted

No changes to the content.

migration/c5a306045ad998f906f80748fe18487f-e474bad466cd6e413fba753746eb58ef/obelisk-handoffdeleted

No changes to the content.

migration/c5a306045ad998f906f80748fe18487f-e474bad466cd6e413fba753746eb58ef/obelisk-upgradedeleted

No changes to the content.

migration/c66bc5ba27dec52d144ceb0aa429e449-1b1686b03b41bd840ff46776cec7b33a/obelisk-handoffdeleted

No changes to the content.

migration/c66bc5ba27dec52d144ceb0aa429e449-1b1686b03b41bd840ff46776cec7b33a/obelisk-upgradedeleted

No changes to the content.

migration/c67f206b6d2626eb6d36b00122b52784-3bc53f3a28cb8f403cc41c11a37eec5d/obelisk-handoffdeleted

No changes to the content.

migration/c67f206b6d2626eb6d36b00122b52784-3bc53f3a28cb8f403cc41c11a37eec5d/obelisk-upgradedeleted

No changes to the content.

migration/c6baede3962454713b73acefcc92fe75-a96d491705acc139315264fd340d228f/obelisk-handoffdeleted

No changes to the content.

migration/c6baede3962454713b73acefcc92fe75-a96d491705acc139315264fd340d228f/obelisk-upgradedeleted

No changes to the content.

migration/c6f38304ee53762590c67020f30d2ab4-58391ba73c13d922e8a12116b28caad2/obelisk-handoffdeleted

No changes to the content.

migration/c6f38304ee53762590c67020f30d2ab4-58391ba73c13d922e8a12116b28caad2/obelisk-upgradedeleted

No changes to the content.

migration/c7dbf17de8aebd3043617ea6db790dcc-d35f6eb2d1b066d366c9a89ab26144e1/obelisk-handoffdeleted

No changes to the content.

migration/c7dbf17de8aebd3043617ea6db790dcc-d35f6eb2d1b066d366c9a89ab26144e1/obelisk-upgradedeleted

No changes to the content.

migration/c801cbcf925c0a7b084ef152e3c08f8e-8d5dba70e93ae7e784ea238281842408/obelisk-handoffdeleted

No changes to the content.

migration/c801cbcf925c0a7b084ef152e3c08f8e-8d5dba70e93ae7e784ea238281842408/obelisk-upgradedeleted

No changes to the content.

migration/c93529e579e64263fd91663216fd3fe7-12c8a24c34c2d8441f3181d179c2baab/obelisk-handoffdeleted

No changes to the content.

migration/c93529e579e64263fd91663216fd3fe7-12c8a24c34c2d8441f3181d179c2baab/obelisk-upgradedeleted

No changes to the content.

migration/ca5ee8f372ecb07b09283081f0298733-36cdb1c744c3036c2932f01d5fadd9f5/obelisk-handoffdeleted

No changes to the content.

migration/ca5ee8f372ecb07b09283081f0298733-36cdb1c744c3036c2932f01d5fadd9f5/obelisk-upgradedeleted

No changes to the content.

migration/ca88f98cf9fb63d2feaef7fc19b30eca-962e2bd1ae8d0c233f8da89ecebffe50/obelisk-handoffdeleted

No changes to the content.

migration/ca88f98cf9fb63d2feaef7fc19b30eca-962e2bd1ae8d0c233f8da89ecebffe50/obelisk-upgradedeleted

No changes to the content.

migration/cb2197d0267b52385ee39bf4adcfe475-fbe0c6b69a63f3a44109a2c7526bc577/obelisk-handoffdeleted

No changes to the content.

migration/cb2197d0267b52385ee39bf4adcfe475-fbe0c6b69a63f3a44109a2c7526bc577/obelisk-upgradedeleted

No changes to the content.

migration/cb2d040cc16752b1dc89eecf200ea798-5734398c41e4eb5bb58d933ed2e12041/obelisk-handoffdeleted

No changes to the content.

migration/cb2d040cc16752b1dc89eecf200ea798-5734398c41e4eb5bb58d933ed2e12041/obelisk-upgradedeleted

No changes to the content.

migration/cb98f93880e6dea74014976977d6eb93-a7c7b80a875d1863f027c97eb433b884/obelisk-handoffdeleted

No changes to the content.

migration/cb98f93880e6dea74014976977d6eb93-a7c7b80a875d1863f027c97eb433b884/obelisk-upgradedeleted

No changes to the content.

migration/cba28ee4b736cf8ed43cb342ccaef12e-8e01c7fee83aa74229a77772d8c928f3/obelisk-handoffdeleted

No changes to the content.

migration/cba28ee4b736cf8ed43cb342ccaef12e-8e01c7fee83aa74229a77772d8c928f3/obelisk-upgradedeleted

No changes to the content.

migration/cbe155a3e856fb7eaad0bd18feb408be-4c9372bf9aa6ebed1ea20abf3dbb0075/obelisk-handoffdeleted

No changes to the content.

migration/cbe155a3e856fb7eaad0bd18feb408be-4c9372bf9aa6ebed1ea20abf3dbb0075/obelisk-upgradedeleted

No changes to the content.

migration/cc4307fc88e3486b1c3f9ce07db95808-0fba399e046852d4ecf8e1dad831a2f9/obelisk-handoffdeleted

No changes to the content.

migration/cc4307fc88e3486b1c3f9ce07db95808-0fba399e046852d4ecf8e1dad831a2f9/obelisk-upgradedeleted

No changes to the content.

migration/ccadc106cd03c9c32e77457d3adc77a1-aa8e6712fd46824acdea303068634078/obelisk-handoffdeleted

No changes to the content.

migration/ccadc106cd03c9c32e77457d3adc77a1-aa8e6712fd46824acdea303068634078/obelisk-upgradedeleted

No changes to the content.

migration/cccf4140dc336263489bcf67c8c58f86-d50a30fd9643486c5848399d5ba7f1f1/obelisk-handoffdeleted

No changes to the content.

migration/cccf4140dc336263489bcf67c8c58f86-d50a30fd9643486c5848399d5ba7f1f1/obelisk-upgradedeleted

No changes to the content.

migration/cd38e239c47fb92fabd867b7f86fc99a-7447d29f4712c72458c049cdb9380753/obelisk-handoffdeleted

No changes to the content.

migration/cd38e239c47fb92fabd867b7f86fc99a-7447d29f4712c72458c049cdb9380753/obelisk-upgradedeleted

No changes to the content.

migration/cd5b54d21dd0fb868f48624d41021f47-0fe60df438daa8a2cca5f2b569e361a5/obelisk-handoffdeleted

No changes to the content.

migration/cd5b54d21dd0fb868f48624d41021f47-0fe60df438daa8a2cca5f2b569e361a5/obelisk-upgradedeleted

No changes to the content.

migration/cd86427cc2d5b2e931d7ab03deb19d20-bd8f5fa095c3eb19b87d85247b36f1df/obelisk-handoffdeleted

No changes to the content.

migration/cd86427cc2d5b2e931d7ab03deb19d20-bd8f5fa095c3eb19b87d85247b36f1df/obelisk-upgradedeleted

No changes to the content.

migration/ce7f0d15d71d36d4bcf4fbadcdfa1b58-4db97ca86399c557e5ee0d04d0838acc/obelisk-handoffdeleted

No changes to the content.

migration/ce7f0d15d71d36d4bcf4fbadcdfa1b58-4db97ca86399c557e5ee0d04d0838acc/obelisk-upgradedeleted

No changes to the content.

migration/cffcc6cab6080a35b7bf7c5c7facd6bc-5631293b75143d170b8fca5579e15fee/obelisk-handoffdeleted

No changes to the content.

migration/cffcc6cab6080a35b7bf7c5c7facd6bc-5631293b75143d170b8fca5579e15fee/obelisk-upgradedeleted

No changes to the content.

migration/d125109aa22f485d282f6ceb7cd5936e-9b9d73736773550dde7d36de2498b029/obelisk-handoffdeleted

No changes to the content.

migration/d125109aa22f485d282f6ceb7cd5936e-9b9d73736773550dde7d36de2498b029/obelisk-upgradedeleted

No changes to the content.

migration/d16784e9a2d93db7f953941e3003fa8c-a262678b7d849de5a9732d06199666ae/obelisk-handoffdeleted

No changes to the content.

migration/d16784e9a2d93db7f953941e3003fa8c-a262678b7d849de5a9732d06199666ae/obelisk-upgradedeleted

No changes to the content.

migration/d17b41a4669ac17960559614c830d69a-66f7a274206ad9f6d3c5701e4bcffc9d/obelisk-handoffdeleted

No changes to the content.

migration/d17b41a4669ac17960559614c830d69a-66f7a274206ad9f6d3c5701e4bcffc9d/obelisk-upgradedeleted

No changes to the content.

migration/d1b3f5f5375558bf91d55c88547784b9-c0811b664036c7996fcfd19fee241a10/obelisk-handoffdeleted

No changes to the content.

migration/d1b3f5f5375558bf91d55c88547784b9-c0811b664036c7996fcfd19fee241a10/obelisk-upgradedeleted

No changes to the content.

migration/d207ab99328b8ece5fb27fa1f4dbf9f6-e6a85005bd7e5d343bc23e17bfc345f6/obelisk-handoffdeleted

No changes to the content.

migration/d207ab99328b8ece5fb27fa1f4dbf9f6-e6a85005bd7e5d343bc23e17bfc345f6/obelisk-upgradedeleted

No changes to the content.

migration/d2d86ce0ca16b143b49374302a9e9e2f-84f4d5c5491abb855d8dbe3acf3bc8e6/obelisk-handoffdeleted

No changes to the content.

migration/d2d86ce0ca16b143b49374302a9e9e2f-84f4d5c5491abb855d8dbe3acf3bc8e6/obelisk-upgradedeleted

No changes to the content.

migration/d327ceb69d24e40dc11792840454cff9-de469e6488ddf192f2104ec0a030daf7/obelisk-handoffdeleted

No changes to the content.

migration/d327ceb69d24e40dc11792840454cff9-de469e6488ddf192f2104ec0a030daf7/obelisk-upgradedeleted

No changes to the content.

migration/d35f6eb2d1b066d366c9a89ab26144e1-03b9747848d7f3e995b118f776ef96c7/obelisk-handoffdeleted

No changes to the content.

migration/d35f6eb2d1b066d366c9a89ab26144e1-03b9747848d7f3e995b118f776ef96c7/obelisk-upgradedeleted

No changes to the content.

migration/d37d70fe5d7d11e68b59ce12022281c9-5f0d3f7480d67df7deebdb880726b356/obelisk-handoffdeleted

No changes to the content.

migration/d37d70fe5d7d11e68b59ce12022281c9-5f0d3f7480d67df7deebdb880726b356/obelisk-upgradedeleted

No changes to the content.

migration/d40e0e3051a76c4c198cc11c2e8e4b7c-1859cc62bb2f89f528bb2aa170c36e84/obelisk-handoffdeleted

No changes to the content.

migration/d40e0e3051a76c4c198cc11c2e8e4b7c-1859cc62bb2f89f528bb2aa170c36e84/obelisk-upgradedeleted

No changes to the content.

migration/d50a30fd9643486c5848399d5ba7f1f1-1f5b6e2a19c87d3820b953f942ab4a27/obelisk-handoffdeleted

No changes to the content.

migration/d50a30fd9643486c5848399d5ba7f1f1-1f5b6e2a19c87d3820b953f942ab4a27/obelisk-upgradedeleted

No changes to the content.

migration/d532356dfb65a4c8a39452d2ebca2516-bf81caf2a7d528f86acacc1f5d2ffcfa/obelisk-handoffdeleted

No changes to the content.

migration/d532356dfb65a4c8a39452d2ebca2516-bf81caf2a7d528f86acacc1f5d2ffcfa/obelisk-upgradedeleted

No changes to the content.

migration/d5ba6f13296205e5bd88ca2756107df0-26a2491fc8a9658751c1511c777a67bd/obelisk-handoffdeleted

No changes to the content.

migration/d5ba6f13296205e5bd88ca2756107df0-26a2491fc8a9658751c1511c777a67bd/obelisk-upgradedeleted

No changes to the content.

migration/d62d6d443d9c2261b7e09664398aa005-fcc617e973168e1210379a6afe7171be/obelisk-handoffdeleted

No changes to the content.

migration/d62d6d443d9c2261b7e09664398aa005-fcc617e973168e1210379a6afe7171be/obelisk-upgradedeleted

No changes to the content.

migration/d6a3ea5f7eb3c95f5e5ea09fb1330270-bc7688ff47218c0e13d02d917b03caa0/obelisk-handoffdeleted

No changes to the content.

migration/d6a3ea5f7eb3c95f5e5ea09fb1330270-bc7688ff47218c0e13d02d917b03caa0/obelisk-upgradedeleted

No changes to the content.

migration/d6b34eba6ed4f89875a6615fe2c41ec2-3daecb03985f83d8af466a9e0541782b/obelisk-handoffdeleted

No changes to the content.

migration/d6b34eba6ed4f89875a6615fe2c41ec2-3daecb03985f83d8af466a9e0541782b/obelisk-upgradedeleted

No changes to the content.

migration/d6c090699acd25fc60213ff4bd9eebcf-0298e61f6a03e553df08dcef03e27bd1/obelisk-handoffdeleted

No changes to the content.

migration/d6c090699acd25fc60213ff4bd9eebcf-0298e61f6a03e553df08dcef03e27bd1/obelisk-upgradedeleted

No changes to the content.

migration/d6cacd7f4fab95c4b6aa2d6c1a4ad2a0-4d6197d8166de78f882376102e36300b/obelisk-handoffdeleted

No changes to the content.

migration/d6cacd7f4fab95c4b6aa2d6c1a4ad2a0-4d6197d8166de78f882376102e36300b/obelisk-upgradedeleted

No changes to the content.

migration/d747c3d0620b2034aca44265dd1c8c86-eeb970434a53f4883c9f0255db555581/obelisk-handoffdeleted

No changes to the content.

migration/d747c3d0620b2034aca44265dd1c8c86-eeb970434a53f4883c9f0255db555581/obelisk-upgradedeleted

No changes to the content.

migration/d8adb57b2f2266e128ebb6f6d7e65920-ccadc106cd03c9c32e77457d3adc77a1/obelisk-handoffdeleted

No changes to the content.

migration/d8adb57b2f2266e128ebb6f6d7e65920-ccadc106cd03c9c32e77457d3adc77a1/obelisk-upgradedeleted

No changes to the content.

migration/da23605ee4058c8474687e74a3999354-dfd7dbceea141c60bbfca962d50c1c06/obelisk-handoffdeleted

No changes to the content.

migration/da23605ee4058c8474687e74a3999354-dfd7dbceea141c60bbfca962d50c1c06/obelisk-upgradedeleted

No changes to the content.

migration/db327f87e60d4e59bdbfd482e5abe985-eb99c1a66237ba99cd1f6d244cafb9cc/obelisk-handoffdeleted

No changes to the content.

migration/db327f87e60d4e59bdbfd482e5abe985-eb99c1a66237ba99cd1f6d244cafb9cc/obelisk-upgradedeleted

No changes to the content.

migration/dc95f39fb27634ccbca7318ff2065608-0fb3a912a8aaf5ef6f734a25f0bce7e2/obelisk-handoffdeleted

No changes to the content.

migration/dc95f39fb27634ccbca7318ff2065608-0fb3a912a8aaf5ef6f734a25f0bce7e2/obelisk-upgradedeleted

No changes to the content.

migration/dd6ca52a58ea6cda7b3eaa2e87bb13d9-a6d50c7e756dfd1e3ae891111b81a1ae/obelisk-handoffdeleted

No changes to the content.

migration/dd6ca52a58ea6cda7b3eaa2e87bb13d9-a6d50c7e756dfd1e3ae891111b81a1ae/obelisk-upgradedeleted

No changes to the content.

migration/ddaa8e0e42a1ef00154d580a390c9f17-53d29061537ddaf7530aef88624ab266/obelisk-handoffdeleted

No changes to the content.

migration/ddaa8e0e42a1ef00154d580a390c9f17-53d29061537ddaf7530aef88624ab266/obelisk-upgradedeleted

No changes to the content.

migration/de469e6488ddf192f2104ec0a030daf7-3da7d4a3b507d18097a90becf4dde9aa/obelisk-handoffdeleted

No changes to the content.

migration/de469e6488ddf192f2104ec0a030daf7-3da7d4a3b507d18097a90becf4dde9aa/obelisk-upgradedeleted

No changes to the content.

migration/df71cd82e801ca701bf4bc44b80b6d50-f423ecd4d096de9dca37a67b8b4143eb/obelisk-handoffdeleted

No changes to the content.

migration/df71cd82e801ca701bf4bc44b80b6d50-f423ecd4d096de9dca37a67b8b4143eb/obelisk-upgradedeleted

No changes to the content.

migration/dfd7dbceea141c60bbfca962d50c1c06-030ed18dacf3571cbb9e3e7d9d99627b/obelisk-handoffdeleted

No changes to the content.

migration/dfd7dbceea141c60bbfca962d50c1c06-030ed18dacf3571cbb9e3e7d9d99627b/obelisk-upgradedeleted

No changes to the content.

migration/e01cc01684deaf4c75ad5d65270bf3d5-c7dbf17de8aebd3043617ea6db790dcc/obelisk-handoffdeleted

No changes to the content.

migration/e01cc01684deaf4c75ad5d65270bf3d5-c7dbf17de8aebd3043617ea6db790dcc/obelisk-upgradedeleted

No changes to the content.

migration/e1ef432db54d9a6daa9bdeeb543262ae-2ba356b187db8db13b8aa40f43ca025f/obelisk-handoffdeleted

No changes to the content.

migration/e1ef432db54d9a6daa9bdeeb543262ae-2ba356b187db8db13b8aa40f43ca025f/obelisk-upgradedeleted

No changes to the content.

migration/e22c51145e08d4a089003460ae80a7f9-42357310c09e345f9360259c6c4102f2/obelisk-handoffdeleted

No changes to the content.

migration/e22c51145e08d4a089003460ae80a7f9-42357310c09e345f9360259c6c4102f2/obelisk-upgradedeleted

No changes to the content.

migration/e24a771ee59f24e45afc0a27307f2070-2eb907820012f77e60350430d89631fe/obelisk-handoffdeleted

No changes to the content.

migration/e24a771ee59f24e45afc0a27307f2070-2eb907820012f77e60350430d89631fe/obelisk-upgradedeleted

No changes to the content.

migration/e2706f337218a12a3bdddd18fa3f4cfd-475f9a0d63e84e9cf13b8be3986cb603/obelisk-handoffdeleted

No changes to the content.

migration/e2706f337218a12a3bdddd18fa3f4cfd-475f9a0d63e84e9cf13b8be3986cb603/obelisk-upgradedeleted

No changes to the content.

migration/e2b2d878b0ba6eb653b194523bf0a0e0-5f307639ccf6a64309166bfe58037397/obelisk-handoffdeleted

No changes to the content.

migration/e2b2d878b0ba6eb653b194523bf0a0e0-5f307639ccf6a64309166bfe58037397/obelisk-upgradedeleted

No changes to the content.

migration/e2be519915794ef130249f2be7640382-455279b6974b96a673613cd0ccc8ed54/obelisk-handoffdeleted

No changes to the content.

migration/e2be519915794ef130249f2be7640382-455279b6974b96a673613cd0ccc8ed54/obelisk-upgradedeleted

No changes to the content.

migration/e323ce1352e512109f1609276fb509b4-2c1521e5a5be64e6d28a9fdae950cd76/obelisk-handoffdeleted

No changes to the content.

migration/e323ce1352e512109f1609276fb509b4-2c1521e5a5be64e6d28a9fdae950cd76/obelisk-upgradedeleted

No changes to the content.

migration/e327773e1525eaa1eb2112dff8f41b26-f595b01939b4c87b7c146ea9ff331b39/obelisk-handoffdeleted

No changes to the content.

migration/e327773e1525eaa1eb2112dff8f41b26-f595b01939b4c87b7c146ea9ff331b39/obelisk-upgradedeleted

No changes to the content.

migration/e3b3014d7e0dc983fe118d32546654e5-063665b78b6705e7de952f73fa9797bf/obelisk-handoffdeleted

No changes to the content.

migration/e3b3014d7e0dc983fe118d32546654e5-063665b78b6705e7de952f73fa9797bf/obelisk-upgradedeleted

No changes to the content.

migration/e4051219d89b3c9a8350fe824ad96a82-166c5f8e4a0f1dfd227b075a96237386/obelisk-handoffdeleted

No changes to the content.

migration/e4051219d89b3c9a8350fe824ad96a82-166c5f8e4a0f1dfd227b075a96237386/obelisk-upgradedeleted

No changes to the content.

migration/e4513b485b6ba8b7f4bd34b12458ff0c-3c80eccfe80d0abd36b07bb11e69fc7a/obelisk-handoffdeleted

No changes to the content.

migration/e4513b485b6ba8b7f4bd34b12458ff0c-3c80eccfe80d0abd36b07bb11e69fc7a/obelisk-upgradedeleted

No changes to the content.

migration/e474bad466cd6e413fba753746eb58ef-f19b3699616f3b1de3a277f9cba617c7/obelisk-handoffdeleted

No changes to the content.

migration/e474bad466cd6e413fba753746eb58ef-f19b3699616f3b1de3a277f9cba617c7/obelisk-upgradedeleted

No changes to the content.

migration/e4b89dd259f3831bc60b56147b3586a6-98da197f133bca81e533ab5ffbf4c82d/obelisk-handoffdeleted

No changes to the content.

migration/e4b89dd259f3831bc60b56147b3586a6-98da197f133bca81e533ab5ffbf4c82d/obelisk-upgradedeleted

No changes to the content.

migration/e609d945b642fd9d4ce99931e3699db7-85c2c4fb8472d50eaa97aed0bdc9b142/obelisk-handoffdeleted

No changes to the content.

migration/e609d945b642fd9d4ce99931e3699db7-85c2c4fb8472d50eaa97aed0bdc9b142/obelisk-upgradedeleted

No changes to the content.

migration/e6980e47ba847245dfab61fb4d5b8ce5-58f9d23d2cede2081dc6f6cfa2283f60/obelisk-handoffdeleted

No changes to the content.

migration/e6980e47ba847245dfab61fb4d5b8ce5-58f9d23d2cede2081dc6f6cfa2283f60/obelisk-upgradedeleted

No changes to the content.

migration/e6a85005bd7e5d343bc23e17bfc345f6-98f9e0bbd21e36b0f4daa440d11e7177/obelisk-handoffdeleted

No changes to the content.

migration/e6a85005bd7e5d343bc23e17bfc345f6-98f9e0bbd21e36b0f4daa440d11e7177/obelisk-upgradedeleted

No changes to the content.

migration/e7288bb723a4e5b7139ac67842963287-7b75ffdcd86b5a330d9c325ad5767393/obelisk-handoffdeleted

No changes to the content.

migration/e7288bb723a4e5b7139ac67842963287-7b75ffdcd86b5a330d9c325ad5767393/obelisk-upgradedeleted

No changes to the content.

migration/e7385c9eae2b807a483b73be4295b207-fb02559b6f723d599e12931a81be3a1b/obelisk-handoffdeleted

No changes to the content.

migration/e7385c9eae2b807a483b73be4295b207-fb02559b6f723d599e12931a81be3a1b/obelisk-upgradedeleted

No changes to the content.

migration/e7667778f2ab3055aa3ccc68443d14df-7adece557941a7d7ac7c150f77f758be/obelisk-handoffdeleted

No changes to the content.

migration/e7667778f2ab3055aa3ccc68443d14df-7adece557941a7d7ac7c150f77f758be/obelisk-upgradedeleted

No changes to the content.

migration/e78ec85bec14f4784faeef4d8d3e4d0a-e7667778f2ab3055aa3ccc68443d14df/obelisk-handoffdeleted

No changes to the content.

migration/e78ec85bec14f4784faeef4d8d3e4d0a-e7667778f2ab3055aa3ccc68443d14df/obelisk-upgradedeleted

No changes to the content.

migration/e7b17aa124e17c357cead8081a58f089-ac5e28caddd6832d0bf1f7445a4a6a28/obelisk-handoffdeleted

No changes to the content.

migration/e7b17aa124e17c357cead8081a58f089-ac5e28caddd6832d0bf1f7445a4a6a28/obelisk-upgradedeleted

No changes to the content.

migration/e7b566495114e160f1f4d722b7ed8174-7cf814f7404638f1c1be662a24d7cfea/obelisk-handoffdeleted

No changes to the content.

migration/e7b566495114e160f1f4d722b7ed8174-7cf814f7404638f1c1be662a24d7cfea/obelisk-upgradedeleted

No changes to the content.

migration/e92786eaf56c32fd6b452c4a841d6317-f24a7fb6e3261c4919ea2a2fee83ed6b/obelisk-handoffdeleted

No changes to the content.

migration/e92786eaf56c32fd6b452c4a841d6317-f24a7fb6e3261c4919ea2a2fee83ed6b/obelisk-upgradedeleted

No changes to the content.

migration/e9ec84bfe7099b713c0fda32308f5815-f0a064ca5f709233204168c136b99a7e/obelisk-handoffdeleted

No changes to the content.

migration/e9ec84bfe7099b713c0fda32308f5815-f0a064ca5f709233204168c136b99a7e/obelisk-upgradedeleted

No changes to the content.

migration/eb99c1a66237ba99cd1f6d244cafb9cc-da23605ee4058c8474687e74a3999354/obelisk-handoffdeleted

No changes to the content.

migration/eb99c1a66237ba99cd1f6d244cafb9cc-da23605ee4058c8474687e74a3999354/obelisk-upgradedeleted

No changes to the content.

migration/ebb95c5864d1d1d2f78fbf7cc8235dac-ba4829dc61dcc12bcafd8de5fc8a76dc/obelisk-handoffdeleted

No changes to the content.

migration/ebb95c5864d1d1d2f78fbf7cc8235dac-ba4829dc61dcc12bcafd8de5fc8a76dc/obelisk-upgradedeleted

No changes to the content.

migration/ec11d10a6131abca9222a8f8026fb5e4-f3d494ffee7091cd588bbdd2fd9bcdf9/obelisk-handoffdeleted

No changes to the content.

migration/ec11d10a6131abca9222a8f8026fb5e4-f3d494ffee7091cd588bbdd2fd9bcdf9/obelisk-upgradedeleted

No changes to the content.

migration/ec94619fa3f25db1ca84d179e47db1ca-23af4d9671962484de53f537a0626d83/obelisk-handoffdeleted

No changes to the content.

migration/ec94619fa3f25db1ca84d179e47db1ca-23af4d9671962484de53f537a0626d83/obelisk-upgradedeleted

No changes to the content.

migration/ed95a99cdde4adc90c6a8e2de82410eb-1c4fc23cbf5653613c6060668e065f37/obelisk-handoffdeleted

No changes to the content.

migration/ed95a99cdde4adc90c6a8e2de82410eb-1c4fc23cbf5653613c6060668e065f37/obelisk-upgradedeleted

No changes to the content.

migration/ee3dccc89ea6fdaaf9c1146b92861e90-f3eac05465851232f8174a7a347d1c4b/obelisk-handoffdeleted

No changes to the content.

migration/ee3dccc89ea6fdaaf9c1146b92861e90-f3eac05465851232f8174a7a347d1c4b/obelisk-upgradedeleted

No changes to the content.

migration/eeb970434a53f4883c9f0255db555581-a2b33f8dc1f90b8dddce942b174be5b8/obelisk-handoffdeleted

No changes to the content.

migration/eeb970434a53f4883c9f0255db555581-a2b33f8dc1f90b8dddce942b174be5b8/obelisk-upgradedeleted

No changes to the content.

migration/ef33c06500054e09c97eee9e9c55485a-367616bd36eda757f251a5e8e9096acc/obelisk-handoffdeleted

No changes to the content.

migration/ef33c06500054e09c97eee9e9c55485a-367616bd36eda757f251a5e8e9096acc/obelisk-upgradedeleted

No changes to the content.

migration/ef6aebc8cba2af6c4f930c981b06e8ac-d17b41a4669ac17960559614c830d69a/obelisk-handoffdeleted

No changes to the content.

migration/ef6aebc8cba2af6c4f930c981b06e8ac-d17b41a4669ac17960559614c830d69a/obelisk-upgradedeleted

No changes to the content.

migration/f0a064ca5f709233204168c136b99a7e-ef6aebc8cba2af6c4f930c981b06e8ac/obelisk-handoffdeleted

No changes to the content.

migration/f0a064ca5f709233204168c136b99a7e-ef6aebc8cba2af6c4f930c981b06e8ac/obelisk-upgradedeleted

No changes to the content.

migration/f15c9c2f894c8cc4fac07e2cdef47180-94252585266fa745a91733888e2f50b7/obelisk-handoffdeleted

No changes to the content.

migration/f15c9c2f894c8cc4fac07e2cdef47180-94252585266fa745a91733888e2f50b7/obelisk-upgradedeleted

No changes to the content.

migration/f19b3699616f3b1de3a277f9cba617c7-4d85ee8cdb0db20a5662b09567a2bbe7/obelisk-handoffdeleted

No changes to the content.

migration/f19b3699616f3b1de3a277f9cba617c7-4d85ee8cdb0db20a5662b09567a2bbe7/obelisk-upgradedeleted

No changes to the content.

migration/f24a7fb6e3261c4919ea2a2fee83ed6b-f913f01e90549c56a8b05f8100cfa21d/obelisk-handoffdeleted

No changes to the content.

migration/f24a7fb6e3261c4919ea2a2fee83ed6b-f913f01e90549c56a8b05f8100cfa21d/obelisk-upgradedeleted

No changes to the content.

migration/f2a9ba4a93c3a04acbee2211bca9e27a-ec94619fa3f25db1ca84d179e47db1ca/obelisk-handoffdeleted

No changes to the content.

migration/f2a9ba4a93c3a04acbee2211bca9e27a-ec94619fa3f25db1ca84d179e47db1ca/obelisk-upgradedeleted

No changes to the content.

migration/f391c6a74ee14217ce4565c278fceed6-e7288bb723a4e5b7139ac67842963287/obelisk-handoffdeleted

No changes to the content.

migration/f391c6a74ee14217ce4565c278fceed6-e7288bb723a4e5b7139ac67842963287/obelisk-upgradedeleted

No changes to the content.

migration/f3d494ffee7091cd588bbdd2fd9bcdf9-b68a785fbf27a63334ef1d1fe82b2dac/obelisk-handoffdeleted

No changes to the content.

migration/f3d494ffee7091cd588bbdd2fd9bcdf9-b68a785fbf27a63334ef1d1fe82b2dac/obelisk-upgradedeleted

No changes to the content.

migration/f3eac05465851232f8174a7a347d1c4b-1629d0d70e360df6b2280fac36d21e8a/obelisk-handoffdeleted

No changes to the content.

migration/f3eac05465851232f8174a7a347d1c4b-1629d0d70e360df6b2280fac36d21e8a/obelisk-upgradedeleted

No changes to the content.

migration/f3ec62d09836804e39fad9d814137845-ef33c06500054e09c97eee9e9c55485a/obelisk-handoffdeleted

No changes to the content.

migration/f3ec62d09836804e39fad9d814137845-ef33c06500054e09c97eee9e9c55485a/obelisk-upgradedeleted

No changes to the content.

migration/f41b690c74938e347cf042cee2d4fc72-7fc381538805adac19c54b73ea118601/obelisk-handoffdeleted

No changes to the content.

migration/f41b690c74938e347cf042cee2d4fc72-7fc381538805adac19c54b73ea118601/obelisk-upgradedeleted

No changes to the content.

migration/f423ecd4d096de9dca37a67b8b4143eb-469a31d20d69da72e6a3a3ea2bb02f9d/obelisk-handoffdeleted

No changes to the content.

migration/f423ecd4d096de9dca37a67b8b4143eb-469a31d20d69da72e6a3a3ea2bb02f9d/obelisk-upgradedeleted

No changes to the content.

migration/f595b01939b4c87b7c146ea9ff331b39-4da182e21be35feeee484dc85be7a075/obelisk-handoffdeleted

No changes to the content.

migration/f595b01939b4c87b7c146ea9ff331b39-4da182e21be35feeee484dc85be7a075/obelisk-upgradedeleted

No changes to the content.

migration/f68462dc88ed7fc451d1c757c040cfee-589eb89cdb09655c5edde4cd2a4deb80/obelisk-handoffdeleted

No changes to the content.

migration/f68462dc88ed7fc451d1c757c040cfee-589eb89cdb09655c5edde4cd2a4deb80/obelisk-upgradedeleted

No changes to the content.

migration/f790ac9400501511b4ee045e22bc5fe1-a826f01311fe00ef5cf87568832605d3/obelisk-handoffdeleted

No changes to the content.

migration/f790ac9400501511b4ee045e22bc5fe1-a826f01311fe00ef5cf87568832605d3/obelisk-upgradedeleted

No changes to the content.

migration/f8e51a9e8ac6598f7c073b09e4ba09b5-ff57aebc7325bd7e02b436fec79e799c/obelisk-handoffdeleted

No changes to the content.

migration/f8e51a9e8ac6598f7c073b09e4ba09b5-ff57aebc7325bd7e02b436fec79e799c/obelisk-upgradedeleted

No changes to the content.

migration/f8eee9431c8b7a767d96da0a8cfae95d-9e05cc6b81c6380ba0ac59bad1021cac/obelisk-handoffdeleted

No changes to the content.

migration/f8eee9431c8b7a767d96da0a8cfae95d-9e05cc6b81c6380ba0ac59bad1021cac/obelisk-upgradedeleted

No changes to the content.

migration/f913f01e90549c56a8b05f8100cfa21d-001efbbe866b66eebc6ee1ea0a906f2d/obelisk-handoffdeleted

No changes to the content.

migration/f913f01e90549c56a8b05f8100cfa21d-001efbbe866b66eebc6ee1ea0a906f2d/obelisk-upgradedeleted

No changes to the content.

migration/f9716ad47c84e0b7ac7d426e8ad059f3-ec11d10a6131abca9222a8f8026fb5e4/obelisk-handoffdeleted

No changes to the content.

migration/f9716ad47c84e0b7ac7d426e8ad059f3-ec11d10a6131abca9222a8f8026fb5e4/obelisk-upgradedeleted

No changes to the content.

migration/f98b82f5d142ce83733a3f18bdacb138-35acc1e0c4d9c02d60abd116f3df84ee/obelisk-handoffdeleted

No changes to the content.

migration/f98b82f5d142ce83733a3f18bdacb138-35acc1e0c4d9c02d60abd116f3df84ee/obelisk-upgradedeleted

No changes to the content.

migration/f9ad863c0bebc103f8b81afdf82e6293-c6f38304ee53762590c67020f30d2ab4/obelisk-handoffdeleted

No changes to the content.

migration/f9ad863c0bebc103f8b81afdf82e6293-c6f38304ee53762590c67020f30d2ab4/obelisk-upgradedeleted

No changes to the content.

migration/fa18f7522903a21b615dbee24c26bfbe-0535e06dd0d61f3e6970b491a17cf1f8/obelisk-handoffdeleted

No changes to the content.

migration/fa18f7522903a21b615dbee24c26bfbe-0535e06dd0d61f3e6970b491a17cf1f8/obelisk-upgradedeleted

No changes to the content.

migration/fb02559b6f723d599e12931a81be3a1b-71a47d4d6856c1956c0d1c9de9af231f/obelisk-handoffdeleted

No changes to the content.

migration/fb02559b6f723d599e12931a81be3a1b-71a47d4d6856c1956c0d1c9de9af231f/obelisk-upgradedeleted

No changes to the content.

migration/fb374b0721716a1e849e64daf6da73c4-f8e51a9e8ac6598f7c073b09e4ba09b5/obelisk-handoffdeleted

No changes to the content.

migration/fb374b0721716a1e849e64daf6da73c4-f8e51a9e8ac6598f7c073b09e4ba09b5/obelisk-upgradedeleted

No changes to the content.

migration/fb5110e527cf77c568bcae7d435ee035-53fdf819333b86dfb485bf16a8f28db2/obelisk-handoffdeleted

No changes to the content.

migration/fb5110e527cf77c568bcae7d435ee035-53fdf819333b86dfb485bf16a8f28db2/obelisk-upgradedeleted

No changes to the content.

migration/fb81153791e49cd00850e91ff7418018-9b33a49f0c978e27b752fa457aca97cc/obelisk-handoffdeleted

No changes to the content.

migration/fb81153791e49cd00850e91ff7418018-9b33a49f0c978e27b752fa457aca97cc/obelisk-upgradedeleted

No changes to the content.

migration/fbb3eb3209281031dc5183d289eb4e75-8c7718f94e2676c957fe844b7dc2637c/obelisk-handoffdeleted

No changes to the content.

migration/fbb3eb3209281031dc5183d289eb4e75-8c7718f94e2676c957fe844b7dc2637c/obelisk-upgradedeleted

No changes to the content.

migration/fbe0c6b69a63f3a44109a2c7526bc577-c3a8b70b1290031feb21880914cb081e/obelisk-handoffdeleted

No changes to the content.

migration/fbe0c6b69a63f3a44109a2c7526bc577-c3a8b70b1290031feb21880914cb081e/obelisk-upgradedeleted

No changes to the content.

migration/fc42c5fc24031fc6a8836a10cfb45143-d125109aa22f485d282f6ceb7cd5936e/obelisk-handoffdeleted

No changes to the content.

migration/fc42c5fc24031fc6a8836a10cfb45143-d125109aa22f485d282f6ceb7cd5936e/obelisk-upgradedeleted

No changes to the content.

migration/fca48edfdaa31b036176b97b04384682-2df092178e167b474dd08dfa46ec3a49/obelisk-handoffdeleted

No changes to the content.

migration/fca48edfdaa31b036176b97b04384682-2df092178e167b474dd08dfa46ec3a49/obelisk-upgradedeleted

No changes to the content.

migration/fcc617e973168e1210379a6afe7171be-ed95a99cdde4adc90c6a8e2de82410eb/obelisk-handoffdeleted

No changes to the content.

migration/fcc617e973168e1210379a6afe7171be-ed95a99cdde4adc90c6a8e2de82410eb/obelisk-upgradedeleted

No changes to the content.

migration/ff1105290f89350bc9deb6eb907e0a53-0c991bc3c06801f72df48486ee78e350/obelisk-handoffdeleted

No changes to the content.

migration/ff1105290f89350bc9deb6eb907e0a53-0c991bc3c06801f72df48486ee78e350/obelisk-upgradedeleted

No changes to the content.

migration/ff57aebc7325bd7e02b436fec79e799c-9f71fc9d2ed805fecbc8c4a3aae5685b/obelisk-handoffdeleted

No changes to the content.

migration/ff57aebc7325bd7e02b436fec79e799c-9f71fc9d2ed805fecbc8c4a3aae5685b/obelisk-upgradedeleted

No changes to the content.

migration/ffa62158ed6fdece012980e4ad25e6ac-959ae2925bcd2b5beff631a8e7aeaf00/obelisk-handoffdeleted

No changes to the content.

migration/ffa62158ed6fdece012980e4ad25e6ac-959ae2925bcd2b5beff631a8e7aeaf00/obelisk-upgradedeleted

No changes to the content.