mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-11-07 01:53:24 +09:00
[Refactor] (P13 W5 S3): record-arm declarations, role-guard stubs and the T0 split in the backends.
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
#include <Includes.h>
|
||||
#include "MG_State/GLState/TextureState/TextureEnum.h"
|
||||
#include <MG_Util/Damage/Damage.h>
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
#include <MG_Pipe/MGPipeHandles.h>
|
||||
#endif
|
||||
|
||||
@@ -37,19 +37,19 @@ namespace MobileGL {
|
||||
struct CopyImageEndpoint {
|
||||
SharedPtr<MG_State::GLState::ITextureObject> Texture;
|
||||
SharedPtr<MG_State::GLState::RenderbufferObject> Renderbuffer;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
MG_Pipe::MGPipeHandle TextureHandle = MG_Pipe::kMGPipeNullHandle;
|
||||
MG_Pipe::MGPipeHandle RenderbufferHandle = MG_Pipe::kMGPipeNullHandle;
|
||||
#endif
|
||||
|
||||
Bool IsRenderbuffer() const {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
if (!MG_Pipe::MGPipeHandleIsNull(RenderbufferHandle)) return true;
|
||||
#endif
|
||||
return Renderbuffer != nullptr;
|
||||
}
|
||||
Bool Exists() const {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
if (!MG_Pipe::MGPipeHandleIsNull(TextureHandle)) return true;
|
||||
if (!MG_Pipe::MGPipeHandleIsNull(RenderbufferHandle)) return true;
|
||||
#endif
|
||||
|
||||
@@ -1180,7 +1180,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
ProcessDeferredBufferReleases();
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
ProcessDeferredT0Retires(); // P11 B2
|
||||
#endif
|
||||
|
||||
@@ -1426,7 +1426,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
ZoneScopedC(TRACY_ZONECOLOR_BACKEND);
|
||||
#endif
|
||||
ProcessDeferredBufferReleases();
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
ProcessDeferredT0Retires(); // P11 B2
|
||||
#endif
|
||||
// THE COMPUTE PATH IS THE ONE THAT NEEDS THE FRONTEND-INDEXED UNIFORM PASS, and it
|
||||
|
||||
@@ -1254,7 +1254,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
return StorageMatchesSize(resource, bufferObject.GetSize());
|
||||
}
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
// -------------------------------------------------------------------------------
|
||||
// R-11 - THE SERVER'S OWN COPY OF THE STAGED BYTES. Package v1.
|
||||
//
|
||||
@@ -1302,7 +1302,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
ServerStaged().RequireCoverage(&resource, hostBase, start, end, site);
|
||||
}
|
||||
}
|
||||
#endif // MOBILEGL_BUILD_RECORD_ARM
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// -------------------------------------------------------------------------------
|
||||
// P11 B2 (T0) - WHEN AN IMPORTED STORE'S AHardwareBuffer MAY BE LET GO.
|
||||
//
|
||||
@@ -1373,6 +1375,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_t0Retired.push_back(retired);
|
||||
SweepT0Retired(false);
|
||||
}
|
||||
#else
|
||||
// No transport, no imported store: nothing ever needs retiring (P13 W5).
|
||||
inline void RetireT0Import(GLESBufferResource&) {}
|
||||
#endif // MOBILEGL_BUILD_DISAGGREGATED
|
||||
|
||||
// The four hostBytes sites read the same in both builds. The non-split expansion is the
|
||||
@@ -3809,7 +3814,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// generation, and a shadow that outlived its twin would be looked up by a RECYCLED
|
||||
// address on the next allocation - which is the quietest possible wrong answer.
|
||||
MGL_SERVER_STAGED_DROP_ALL();
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
// tx's texture shadows die for the same reason, keyed by handle rather than address
|
||||
// but with the same recycled-identity failure mode: a new context's allocator may
|
||||
// hand out a {slot, gen} the old one's store still answers for.
|
||||
@@ -3817,8 +3822,10 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// P11 B2: every retired T0 import's fence named work on the context that just ended,
|
||||
// so all of them let go now. LIVE imports keep their reference: the next ensure
|
||||
// imports them again on the new context (EnsureBufferResourceForHandle).
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
ProcessDeferredT0Retires();
|
||||
SweepT0Retired(/*contextGone=*/true);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -3854,7 +3861,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
}
|
||||
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// P11 B2: the T0 half of the deferred-release drain, run right after it at both sync
|
||||
// points (ProcessDeferredBufferReleases itself moves verbatim, G5). Retired imports whose
|
||||
// fence signalled let go of their AHardwareBuffer; a deferred T0 destroy is retired once
|
||||
|
||||
@@ -476,7 +476,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
if (!EsprytSlotTablesEnabled()) return nullptr;
|
||||
if (MG_Pipe::MGPipeHandleIsNull(handle)) return nullptr;
|
||||
if (handle.Slot >= SlotTable::kMaxHandleSlot) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
MG_Pipe::MGPipeSessionFail( // @Ph-declined (ID-P7-1): PH-2 stays Fatal, CONTRACT-P7 §12
|
||||
MG_Pipe::MGPipeFatalFamily::ProtocolCorruption,
|
||||
"MGPipe: Fatal{ProtocolCorruption, \"BackendSlotTable.HandleSlot\"} - "
|
||||
@@ -488,7 +488,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
}
|
||||
const Uint32 liveGen = m_slotTables.LiveGenAt(handle.Slot);
|
||||
if (liveGen != 0 && liveGen > handle.Gen) {
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
MG_Pipe::MGPipeSessionFail( // @Ph-declined (ID-P7-1): PH-2 stays Fatal, CONTRACT-P7 §12
|
||||
MG_Pipe::MGPipeFatalFamily::ProtocolCorruption,
|
||||
"MGPipe: Fatal{ProtocolCorruption, \"BackendSlotTable.Generation\"} - "
|
||||
@@ -938,7 +938,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// AcquirePersistentMap or (FLUSH_EXPLICIT) publish only via FlushMappedRange.
|
||||
Uint64 CurrentBufferMutationEpoch();
|
||||
void BumpBufferMutationEpoch();
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
// P5e (vi), CONTRACT-P5E §5.1's first pin: how many bumps came from a thread other than
|
||||
// the apply thread WHILE an apply thread was running, under a live transport. The
|
||||
// record arm's clean gate stamps this counter and skips its probes while the stamp
|
||||
@@ -1071,7 +1071,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// the legacy arm did; this member exists for the drains that have no object, which
|
||||
// in P3a is the readback flush and the fp64 narrowing.
|
||||
const Uint8* hostBytes = nullptr;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
// P11 B2 (T0): the client's AHardwareBuffer this store IS - imported with
|
||||
// glBufferStorageExternalEXT, so `id` is immutable, persistentMapped and
|
||||
// persistentPtr is this server's own coherent map of the client's pages. The
|
||||
@@ -1366,7 +1366,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
// Deletes GL buffers whose owning frontend objects died (possibly on a
|
||||
// thread without a current ES context). Called from draw-time sync.
|
||||
void ProcessDeferredBufferReleases();
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
// P11 B2: the T0 half of that drain - run right after it (retired AHardwareBuffers).
|
||||
void ProcessDeferredT0Retires();
|
||||
#endif
|
||||
@@ -3670,7 +3670,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
|
||||
g_backendRenderbufferObjects;
|
||||
} // namespace RenderbufferImpl
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
// P5c (ct), CONTRACT-P5C.md §5.2: object_death's per-kind release, one entry point for all
|
||||
// seven kinds for the same reason the notice switch is one - the answer is the same for
|
||||
// all of them: every holder of the kind's twin table lets go of the twin at this handle.
|
||||
|
||||
@@ -215,7 +215,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Uint32 cursor = 0;
|
||||
};
|
||||
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
// ResolveWireImageDescriptor emits no pNext chain. Key every view-create
|
||||
// value explicitly: hash collisions must never alias different windows,
|
||||
// formats or swizzles. The root handle and allocation epoch also prevent
|
||||
@@ -563,7 +563,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkBuffer uboBuffer = VK_NULL_HANDLE;
|
||||
VkDeviceSize uboRange = 0;
|
||||
VkDescriptorSet set = VK_NULL_HANDLE;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
Uint64 wireStoreDestroyEpoch = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VmaAllocation m_allocation = nullptr;
|
||||
void* m_mappedData = nullptr;
|
||||
VkDeviceSize m_size = 0;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
VkDeviceMemory m_externalMemory = VK_NULL_HANDLE;
|
||||
void* m_externalAhb = nullptr;
|
||||
|
||||
@@ -604,7 +604,7 @@ public:
|
||||
|
||||
TextureResource* SyncTextureAndGetDescriptor(
|
||||
MG_State::GLState::ITextureObject& texture);
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
// P5f (fm): THE HANDLE-KEYED ARM of SyncTextureAndGetDescriptor. Under an active transport
|
||||
// the apply thread may not name the client's ITextureObject (rule E), so the clear / blit /
|
||||
// readback / mipmap verbs resolve their attachment textures from the wire handle the
|
||||
@@ -856,7 +856,7 @@ private:
|
||||
void EraseTrackedTexture(const TextureIdentity& identity);
|
||||
void PruneStaleTextureAliases(MG_State::GLState::ITextureObject* texture);
|
||||
SizeT PruneDeadTextures();
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
// The two halves of SyncTextureResourceByHandle: shape from the resource record's
|
||||
// descriptor (create / recreate / compatibility), then the pending-upload walk against the
|
||||
// server's staged store. UploadPendingWireLevels mutates the applier's record (consumed
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
#include "VkSamplerManager.h"
|
||||
#include "VkTextureManager.h"
|
||||
#include "VkTimerQueryManager.h"
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
#include "GpuProgressMarkers.h"
|
||||
#include "WireRenderPassCompatibility.h"
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#include <MG_Remote/Server/SharedImageRegistry.h>
|
||||
#endif
|
||||
#endif
|
||||
#include "MG_Util/Math/VectorTypes.h"
|
||||
#include <Includes.h>
|
||||
#include <MG_Backend/BackendObject.h>
|
||||
@@ -148,7 +150,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// of the swapchain image acquired for it (SwapchainObject::BufferAgeOf). Asking makes the
|
||||
// target keep its presented images' content from then on.
|
||||
Int32 CurrentDrawBufferAge();
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
VkBufferManager& GetWireBufferManager() { return m_bufferManager; }
|
||||
Bool FlushWirePendingCommandsForTextureUpdate() {
|
||||
// A new texture upload must not race graphics work that samples
|
||||
@@ -629,7 +631,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// See NoteDeviceLoss. Set once, never cleared: a lost VkDevice stays lost.
|
||||
Bool m_deviceLost = false;
|
||||
Bool m_deviceLossLatched = false;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
#if MOBILEGL_BUILD_RECORD_ARM
|
||||
// Brackets this device's frame submissions for the GPU hang watch (LatchIfGpuHung).
|
||||
GpuProgressMarkers m_progressMarkers;
|
||||
struct WireImage {
|
||||
@@ -777,7 +779,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
Uint64 acquireSubmit = 0;
|
||||
};
|
||||
Vector<SharedImageHold> m_sharedImagesHeld;
|
||||
#if MOBILEGL_BUILD_DISAGGREGATED
|
||||
MG_Remote::Server::SharedImages::ReadTracker m_sharedImageReads;
|
||||
#endif
|
||||
Vector<Uint64> m_sharedImageUseScratch;
|
||||
// What one vkQueueSubmit carries beyond its own semaphores (AttachSharedImageSync).
|
||||
struct SharedImageSubmitSync {
|
||||
|
||||
@@ -211,5 +211,19 @@ namespace MobileGL::MG_Pipe {
|
||||
MGPipeFrontendKeyedRegistryScope& operator=(const MGPipeFrontendKeyedRegistryScope&) = delete;
|
||||
};
|
||||
|
||||
#else
|
||||
// P13 W5: no transport, no apply thread - the role guards have nothing to refuse, and the two
|
||||
// scopes nothing to mark (the record arm calls all of them in every build).
|
||||
inline void MGPipeRefuseAllocatorFromApplyThread(const char*) {}
|
||||
inline Bool MGPipeApplierIsUnbarrieredApply() { return false; }
|
||||
inline void MGPipeRefuseFrontendKeyedRegistryFromApplyThread(const char*) {}
|
||||
class MagmaP7AllocatorDebtScope {
|
||||
public:
|
||||
MagmaP7AllocatorDebtScope() = default;
|
||||
};
|
||||
class MGPipeFrontendKeyedRegistryScope {
|
||||
public:
|
||||
MGPipeFrontendKeyedRegistryScope() = default;
|
||||
};
|
||||
#endif
|
||||
} // namespace MobileGL::MG_Pipe
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# P13 W5 S3, round 1: the record arm's declarations (headers).
|
||||
# Magma renderer: progress markers and the wire render-pass table are the record arm's; the shared-image
|
||||
# registry is the transport's.
|
||||
nest | MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h | #include <MG_Remote/Server/SharedImageRegistry.h> | #include <MG_Remote/Server/SharedImageRegistry.h>
|
||||
open | MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h | #include "GpuProgressMarkers.h"
|
||||
open | MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h | VkBufferManager& GetWireBufferManager()
|
||||
open | MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h | GpuProgressMarkers m_progressMarkers;
|
||||
nest | MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h | MG_Remote::Server::SharedImages::ReadTracker m_sharedImageReads; | MG_Remote::Server::SharedImages::ReadTracker m_sharedImageReads;
|
||||
open | MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h | Bool ReadUnbackedWireLevel(
|
||||
open | MobileGL/MG_Backend/DirectVulkan/Renderer/VkTextureManager.h | Bool SyncWireTextureShape(
|
||||
open | MobileGL/MG_Backend/DirectVulkan/Renderer/VkBufferObject.h | VkDeviceMemory m_externalMemory
|
||||
open | MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.h | struct WireImageViewKey {
|
||||
open | MobileGL/MG_Backend/DirectVulkan/Renderer/UniformManager.h | Uint64 wireStoreDestroyEpoch = 0;
|
||||
# Espryt managers: the record-keyed twin tables, the draw-input requests, the buffer twin's record fields,
|
||||
# and the per-object death release (the monolith port drops its twins through it too).
|
||||
open | MobileGL/MG_Backend/DirectGLES/Managers.h | "MGPipe: Fatal{ProtocolCorruption, \"BackendSlotTable.HandleSlot\"} - "
|
||||
open | MobileGL/MG_Backend/DirectGLES/Managers.h | "MGPipe: Fatal{ProtocolCorruption, \"BackendSlotTable.Generation\"} - "
|
||||
open | MobileGL/MG_Backend/DirectGLES/Managers.h | Uint64 BufferMutationEpochBumpsOffTheApplyThread();
|
||||
open | MobileGL/MG_Backend/DirectGLES/Managers.h | Bool serverGpuWritten = false;
|
||||
open | MobileGL/MG_Backend/DirectGLES/Managers.h | Bool ReleaseTwinsForWireObjectDeath(
|
||||
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env python3
|
||||
"""P13 W5 S3: hand-directed guard edits, by content rather than line number.
|
||||
|
||||
w5_regate.py <ops-file>
|
||||
|
||||
Each non-comment line of the ops file is one operation (fields separated by ' | '):
|
||||
open | <path> | <text> the `#if MOBILEGL_BUILD_DISAGGREGATED` group whose first body line
|
||||
contains <text> becomes `#if MOBILEGL_BUILD_RECORD_ARM`
|
||||
(with its #else / #endif comments)
|
||||
nest | <path> | <first> | <last> wrap the lines from the one containing <first> through the one
|
||||
containing <last> (searched after <first>) in
|
||||
`#if MOBILEGL_BUILD_DISAGGREGATED` / `#endif`
|
||||
line | <path> | <text> | <new> replace the one line containing <text> with <new> verbatim
|
||||
Every <text> must match exactly one place (for `open`: exactly one group).
|
||||
"""
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
|
||||
OLD = 'MOBILEGL_BUILD_DISAGGREGATED'
|
||||
NEW = 'MOBILEGL_BUILD_RECORD_ARM'
|
||||
DIRECTIVE = re.compile(r'^\s*#\s*(if|ifdef|ifndef|elif|else|endif)\b(.*)$')
|
||||
|
||||
|
||||
def load(path):
|
||||
raw = pathlib.Path(path).read_bytes().decode('utf-8')
|
||||
return '\r\n' in raw, raw.replace('\r\n', '\n').split('\n')
|
||||
|
||||
|
||||
def save(path, crlf, lines):
|
||||
text = '\n'.join(lines)
|
||||
pathlib.Path(path).write_bytes((text.replace('\n', '\r\n') if crlf else text).encode('utf-8'))
|
||||
|
||||
|
||||
def groups(lines):
|
||||
stack, out = [], []
|
||||
for i, line in enumerate(lines):
|
||||
m = DIRECTIVE.match(line)
|
||||
if not m:
|
||||
continue
|
||||
kind = m.group(1)
|
||||
if kind in ('if', 'ifdef', 'ifndef'):
|
||||
stack.append({'open': i, 'branches': []})
|
||||
elif kind in ('elif', 'else'):
|
||||
if stack:
|
||||
stack[-1]['branches'].append(i)
|
||||
elif stack:
|
||||
g = stack.pop()
|
||||
g['close'] = i
|
||||
out.append(g)
|
||||
return out
|
||||
|
||||
|
||||
def op_open(lines, text):
|
||||
hits = []
|
||||
for g in groups(lines):
|
||||
if not re.match(r'^\s*#\s*if\s+' + OLD + r'\s*(//.*)?$', lines[g['open']]):
|
||||
continue
|
||||
end = g['branches'][0] if g['branches'] else g['close']
|
||||
if any(text in l for l in lines[g['open'] + 1:end]):
|
||||
hits.append(g)
|
||||
# The innermost group that contains the text: drop any group that contains another hit.
|
||||
hits = [g for g in hits if not any(h is not g and g['open'] < h['open'] and h['close'] < g['close'] for h in hits)]
|
||||
if len(hits) != 1:
|
||||
raise SystemExit('open: %d groups contain %r' % (len(hits), text))
|
||||
g = hits[0]
|
||||
for i in [g['open']] + g['branches'] + [g['close']]:
|
||||
lines[i] = lines[i].replace(OLD, NEW)
|
||||
|
||||
|
||||
def find_one(lines, text, start=0):
|
||||
idx = [i for i in range(start, len(lines)) if text in lines[i]]
|
||||
if not idx:
|
||||
raise SystemExit('no line contains %r' % text)
|
||||
if start == 0 and len(idx) != 1:
|
||||
raise SystemExit('%d lines contain %r' % (len(idx), text))
|
||||
return idx[0]
|
||||
|
||||
|
||||
def main():
|
||||
ops = [l for l in pathlib.Path(sys.argv[1]).read_text(encoding='utf-8').splitlines()
|
||||
if l.strip() and not l.lstrip().startswith('#')]
|
||||
files = {}
|
||||
for op in ops:
|
||||
parts = [p.strip() for p in op.split(' | ')]
|
||||
kind, path = parts[0], parts[1]
|
||||
if path not in files:
|
||||
files[path] = load(path)
|
||||
crlf, lines = files[path]
|
||||
if kind == 'open':
|
||||
op_open(lines, parts[2])
|
||||
elif kind == 'nest':
|
||||
a = find_one(lines, parts[2])
|
||||
b = find_one(lines, parts[3], a)
|
||||
lines[b + 1:b + 1] = ['#endif']
|
||||
lines[a:a] = ['#if ' + OLD]
|
||||
elif kind == 'line':
|
||||
a = find_one(lines, parts[2])
|
||||
lines[a] = parts[3]
|
||||
else:
|
||||
raise SystemExit('unknown op ' + kind)
|
||||
for path, (crlf, lines) in files.items():
|
||||
save(path, crlf, lines)
|
||||
print('applied', len(ops), 'op(s) to', len(files), 'file(s)')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user