Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,38 @@
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
},
{
"name": "Docker Attach",
"type": "coreclr",
"request": "attach",
},
]
"processId": "${command:pickRemoteProcess}",
"justMyCode": false,
"requireExactSource": false,
// "symbolOptions": {
// "searchPaths": [ ],
// "searchMicrosoftSymbolServer": false,
// "searchNuGetOrgSymbolServer": false,
// "moduleFilter": {
// "mode": "loadOnlyIncluded",
// "includedModules": [
// "LfMerge*.dll",
// "SIL*.dll",
// ]
// }
// },
"pipeTransport": {
"pipeProgram": "docker",
"pipeArgs": [
"exec",
"-i",
"lfmerge"
],
"debuggerPath": "/vsdbg/vsdbg",
"pipeCwd": "${workspaceRoot}",
"quoteArgs": false
},
}
]
}
13 changes: 12 additions & 1 deletion Dockerfile.finalresult
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# syntax=docker/dockerfile:experimental
ARG DbVersion=7000072
ARG Environment=production

FROM ghcr.io/sillsdev/lfmerge-base:runtime
FROM ghcr.io/sillsdev/lfmerge-base:runtime AS lfmerge-base-runtime

# install LFMerge prerequisites
# tini - PID 1 handler
Expand All @@ -13,6 +14,16 @@ RUN apt-get update \
&& apt-get install --yes --no-install-recommends tini python iputils-ping inotify-tools less vim-tiny \
&& rm -rf /var/lib/apt/lists/*

FROM lfmerge-base-runtime AS lfmerge-base-runtime-development

RUN apt update && \
apt install unzip && \
apt install curl -y && \
curl -sSL https://aka.ms/getvsdbgsh | /bin/sh /dev/stdin -v latest -l /vsdbg

FROM lfmerge-base-runtime AS lfmerge-base-runtime-production
FROM lfmerge-base-runtime-${Environment}

ADD tarball/lfmerge* /

RUN mkdir -m 02775 -p /var/lib/languageforge/lexicon/sendreceive/syncqueue /var/lib/languageforge/lexicon/sendreceive/webwork /var/lib/languageforge/lexicon/sendreceive/Templates /var/lib/languageforge/lexicon/sendreceive/state && chown -R www-data:www-data /var/lib/languageforge
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ For each DbVersion that LfMerge supports, we build a different lfmerge binary. W

## Debugging

Debugging is possible, in some form, with the C# extension in VS Code. Run pbuild.sh (which creates the environment used by the debugger), set your breakpoints, and run the .NET Core Launch task. Due to the complex nature of the software, which necessitates the use of pbuild.sh, for example, there may be custom setup required to progress far enough to reach your breakpoints, depending on where they are. Debugging will launch and use LfQueueManager as its entry point.
Debugging is possible through the "Docker Attach" launch configuration in VS Code. All the expected debugging features are there, including breakpoints, call stack, and source viewing. There is some work left to be done, however: the source used is pulled from GitHub, excluding local changes. The breakpoints work, simply swap between the file pulled from GitHub and the local, comparing line numbers.

If you get your project put on HOLD and need to recover quickly, use the "Attach to Running Container..." command to attach to the "lfmerge" container and change the project state manually (to IDLE) located in `/var/lib/languageforge/lexicon/sendreceive/state/<project-name>.state`.

## Testing locally

Expand Down
3 changes: 2 additions & 1 deletion pbuild.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ set -e
# These are arrays; see https://www.gnu.org/software/bash/manual/html_node/Arrays.html
DBMODEL_VERSIONS=(7000072)
HISTORICAL_VERSIONS=(7000068 7000069 7000070)
Environment=${1:-production}

# In the future when we have more than one model version, we may want to use GNU parallel for building.
# ATTENTION: If GNU parallel is desired, uncomment the below (until the "ATTENTION: Stop uncommenting here" line):
Expand Down Expand Up @@ -80,4 +81,4 @@ for DbVersion in ${DBMODEL_VERSIONS[@]}; do
lfmerge-build-${DbVersion}
done

time docker build -t ghcr.io/sillsdev/lfmerge -f Dockerfile.finalresult .
time docker build -t ghcr.io/sillsdev/lfmerge -f Dockerfile.finalresult . --build-arg Environment=${Environment}
10 changes: 5 additions & 5 deletions src/LfMerge.Core.Tests/Actions/SynchronizeActionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,8 @@ public void SynchronizeAction_LFDataChanged_GlossChanged()
IEnumerable<LfLexEntry> originalMongoData = _mongoConnection.GetLfLexEntries();
LfLexEntry lfEntry = originalMongoData.First(e => e.Guid == _testEntryGuid);
string unchangedGloss = lfEntry.Senses[0].Gloss["en"].Value;
string lfChangedGloss = unchangedGloss + " - changed in LF";
lfEntry.Senses[0].Gloss["en"].Value = lfChangedGloss;
var lfChangedGloss = LfStringField.CreateFrom(unchangedGloss + " - changed in LF");
lfEntry.Senses[0].Gloss["en"] = lfChangedGloss;
_mongoConnection.UpdateRecord(_lfProject, lfEntry);

_lDProject = new LanguageDepotMock(testProjectCode, _lDSettings);
Expand All @@ -186,7 +186,7 @@ public void SynchronizeAction_LFDataChanged_GlossChanged()
Assert.That(GetGlossFromLanguageDepot(_testEntryGuid, 2), Is.EqualTo(lfChangedGloss));
}

[Test, Explicit("Superceeded by later tests")]
[Test, Explicit("Superceded by later tests")]
public void SynchronizeAction_LDDataChanged_GlossChanged()
{
// Setup
Expand Down Expand Up @@ -246,8 +246,8 @@ public void SynchronizeAction_LFDataChangedLDDataChanged_LFWins()

string unchangedGloss = lfEntry.Senses[0].Gloss["en"].Value;
string fwChangedGloss = unchangedGloss + " - changed in FW";
string lfChangedGloss = unchangedGloss + " - changed in LF";
lfEntry.Senses[0].Gloss["en"].Value = lfChangedGloss;
var lfChangedGloss = LfStringField.CreateFrom(unchangedGloss + " - changed in LF");
lfEntry.Senses[0].Gloss["en"] = lfChangedGloss;
lfEntry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
_mongoConnection.UpdateRecord(_lfProject, lfEntry);

Expand Down
53 changes: 27 additions & 26 deletions src/LfMerge.Core.Tests/Lcm/RoundTripTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ public void RoundTrip_LcmToMongoToLcmToMongo_ShouldKeepModifiedValuesInEntries()
string vernacularWS = cache.ServiceLocator.WritingSystemManager.GetStrFromWs(cache.DefaultVernWs);
string originalLexeme = originalLfEntry.Lexeme[vernacularWS].Value;
string changedLexeme = "Changed lexeme for this test";
originalLfEntry.Lexeme[vernacularWS].Value = changedLexeme;
var originalValue = LfStringField.CreateFrom(changedLexeme);
originalLfEntry.Lexeme[vernacularWS] = originalValue;
originalLfEntry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
_conn.UpdateMockLfLexEntry(originalLfEntry);

Expand All @@ -192,7 +193,7 @@ public void RoundTrip_LcmToMongoToLcmToMongo_ShouldKeepModifiedValuesInEntries()
// Exercise
SutMongoToLcm.Run(lfProject);
string changedLexemeDuringUpdate = "This value should be overwritten by LcmToMongo";
originalLfEntry.Lexeme[vernacularWS].Value = changedLexemeDuringUpdate;
originalLfEntry.Lexeme[vernacularWS] = LfStringField.CreateFrom(changedLexemeDuringUpdate);
originalLfEntry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
_conn.UpdateMockLfLexEntry(originalLfEntry);
SutLcmToMongo.Run(lfProject);
Expand Down Expand Up @@ -220,7 +221,7 @@ public void RoundTrip_LcmToMongoToLcmToMongo_ShouldKeepModifiedValuesInEntries()
Assert.That(lfEntry.Lexeme[vernacularWS].Value, Is.Not.EqualTo(changedLexemeDuringUpdate));
Assert.That(lfEntry.Lexeme[vernacularWS].Value, Is.EqualTo(changedLexeme));

originalLfEntry.Lexeme[vernacularWS].Value = originalLexeme;
originalLfEntry.Lexeme[vernacularWS] = originalValue;
differencesByName = GetMongoDifferences(originalLfEntry.ToBsonDocument(), lfEntry.ToBsonDocument());
differencesByName.Remove("lexeme");
differencesByName.Remove("dateModified");
Expand Down Expand Up @@ -266,20 +267,20 @@ public void RoundTrip_LcmToMongoToLcmToMongo_ShouldKeepModifiedValuesInSenses()
LfLexEntry originalEntry = originalData.FirstOrDefault(e => e.Guid.ToString() == TestEntryGuidStr);
Assert.That(originalEntry.Senses.Count, Is.EqualTo(2));

string originalSense0Definition = originalEntry.Senses[0].Definition["en"].Value;
string originalSense1Definition = originalEntry.Senses[1].Definition["en"].Value;
string changedSense0Definition = "Changed sense0 definition for this test";
string changedSense1Definition = "Changed sense1 definition for this test";
originalEntry.Senses[0].Definition["en"].Value = changedSense0Definition;
originalEntry.Senses[1].Definition["en"].Value = changedSense1Definition;
var originalSense0Definition = originalEntry.Senses[0].Definition["en"];
var originalSense1Definition = originalEntry.Senses[1].Definition["en"];
var changedSense0Definition = LfStringField.CreateFrom("Changed sense0 definition for this test");
var changedSense1Definition = LfStringField.CreateFrom("Changed sense1 definition for this test");
originalEntry.Senses[0].Definition["en"] = changedSense0Definition;
originalEntry.Senses[1].Definition["en"] = changedSense1Definition;
originalEntry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
_conn.UpdateMockLfLexEntry(originalEntry);

// Exercise
SutMongoToLcm.Run(lfProject);
string changedDefinitionDuringUpdate = "This value should be overwritten by LcmToMongo";
originalEntry.Senses[0].Definition["en"].Value = changedDefinitionDuringUpdate;
originalEntry.Senses[1].Definition["en"].Value = changedDefinitionDuringUpdate;
var changedDefinitionDuringUpdate = LfStringField.CreateFrom("This value should be overwritten by LcmToMongo");
originalEntry.Senses[0].Definition["en"] = changedDefinitionDuringUpdate;
originalEntry.Senses[1].Definition["en"] = changedDefinitionDuringUpdate;
originalEntry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
_conn.UpdateMockLfLexEntry(originalEntry);

Expand Down Expand Up @@ -318,8 +319,8 @@ public void RoundTrip_LcmToMongoToLcmToMongo_ShouldKeepModifiedValuesInSenses()
Assert.That(lfEntry.Senses[0].Definition["en"].Value, Is.EqualTo(changedSense0Definition));
Assert.That(lfEntry.Senses[1].Definition["en"].Value, Is.EqualTo(changedSense1Definition));

originalEntry.Senses[0].Definition["en"].Value = originalSense0Definition;
originalEntry.Senses[1].Definition["en"].Value = originalSense1Definition;
originalEntry.Senses[0].Definition["en"] = originalSense0Definition;
originalEntry.Senses[1].Definition["en"] = originalSense1Definition;
IDictionary<string, Tuple<string, string>> differencesByName =
GetMongoDifferences(originalEntry.Senses[0].ToBsonDocument(), lfEntry.Senses[0].ToBsonDocument());
differencesByName.Remove("definition");
Expand Down Expand Up @@ -378,20 +379,20 @@ public void RoundTrip_LcmToMongoToLcmToMongo_ShouldKeepModifiedValuesInExample()
Assert.That(originalEntry.Senses.Count, Is.EqualTo(2));
Assert.That(originalEntry.Senses[0].Examples.Count, Is.EqualTo(2));

string originalSense0Example0Translation = originalEntry.Senses[0].Examples[0].Translation["en"].Value;
string originalSense0Example1Translation = originalEntry.Senses[0].Examples[1].Translation["en"].Value;
string changedSense0Example0Translation = "Changed sense0 example0 sentence for this test";
string changedSense0Example1Translation = "Changed sense0 example1 sentence for this test";
originalEntry.Senses[0].Examples[0].Translation["en"].Value = changedSense0Example0Translation;
originalEntry.Senses[0].Examples[1].Translation["en"].Value = changedSense0Example1Translation;
var originalSense0Example0Translation = originalEntry.Senses[0].Examples[0].Translation["en"];
var originalSense0Example1Translation = originalEntry.Senses[0].Examples[1].Translation["en"];
var changedSense0Example0Translation = LfStringField.CreateFrom("Changed sense0 example0 sentence for this test");
var changedSense0Example1Translation = LfStringField.CreateFrom("Changed sense0 example1 sentence for this test");
originalEntry.Senses[0].Examples[0].Translation["en"] = changedSense0Example0Translation;
originalEntry.Senses[0].Examples[1].Translation["en"] = changedSense0Example1Translation;
originalEntry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
_conn.UpdateMockLfLexEntry(originalEntry);

// Exercise
SutMongoToLcm.Run(lfProject);
string changedTranslationDuringUpdate = "This value should be overwritten by LcmToMongo";
originalEntry.Senses[0].Examples[0].Translation["en"].Value = changedTranslationDuringUpdate;
originalEntry.Senses[0].Examples[1].Translation["en"].Value = changedTranslationDuringUpdate;
var changedTranslationDuringUpdate = LfStringField.CreateFrom("This value should be overwritten by LcmToMongo");
originalEntry.Senses[0].Examples[0].Translation["en"] = changedTranslationDuringUpdate;
originalEntry.Senses[0].Examples[1].Translation["en"] = changedTranslationDuringUpdate;
originalEntry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
_conn.UpdateMockLfLexEntry(originalEntry);

Expand Down Expand Up @@ -436,8 +437,8 @@ public void RoundTrip_LcmToMongoToLcmToMongo_ShouldKeepModifiedValuesInExample()
Assert.That(lfEntry.Senses[0].Examples[0].Translation["en"].Value, Is.EqualTo(changedSense0Example0Translation));
Assert.That(lfEntry.Senses[0].Examples[1].Translation["en"].Value, Is.EqualTo(changedSense0Example1Translation));

originalEntry.Senses[0].Examples[0].Translation["en"].Value = originalSense0Example0Translation;
originalEntry.Senses[0].Examples[1].Translation["en"].Value = originalSense0Example1Translation;
originalEntry.Senses[0].Examples[0].Translation["en"] = originalSense0Example0Translation;
originalEntry.Senses[0].Examples[1].Translation["en"] = originalSense0Example1Translation;
IDictionary<string, Tuple<string, string>> differencesByName =
GetMongoDifferences(originalEntry.Senses[0].Examples[0].ToBsonDocument(), lfEntry.Senses[0].Examples[0].ToBsonDocument());
differencesByName.Remove("translation");
Expand Down Expand Up @@ -553,7 +554,7 @@ public void RoundTrip_MongoToLcmToMongo_ShouldAddAndDeleteNewSense()
LfSense newSense = new LfSense();
newSense.Guid = Guid.NewGuid();
newSense.Definition = LfMultiText.FromSingleStringMapping(vernacularWS, newDefinition);
newSense.PartOfSpeech = LfStringField.FromString(newPartOfSpeech);
newSense.PartOfSpeech = new LfOptionListItem { Value = newPartOfSpeech };
lfEntry.Senses.Add(newSense);
Assert.That(lfEntry.Senses.Count, Is.EqualTo(3));
lfEntry.AuthorInfo.ModifiedDate = DateTime.UtcNow;
Expand Down
3 changes: 0 additions & 3 deletions src/LfMerge.Core.Tests/Lcm/TransferLcmToMongoActionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ private IEnumerable<LfOptionListItem> DefaultGrammarItems(int howMany)
string abbrev = PartOfSpeechMasterList.FlatPosAbbrevs[guidStr];
yield return new LfOptionListItem {
Guid = Guid.Parse(guidStr),
Key = abbrev,
Abbreviation = abbrev,
Value = name,
};
Expand Down Expand Up @@ -242,7 +241,6 @@ public void Action_WithPreviousMongoGrammarWithMatchingGuids_ShouldBeUpdatedFrom
Guid g = itemForTest.Guid.Value;
itemForTest.Abbreviation = "Different abbreviation";
itemForTest.Value = "Different name";
itemForTest.Key = "Different key";
_conn.UpdateMockOptionList(lfGrammar);

// Exercise
Expand All @@ -258,7 +256,6 @@ public void Action_WithPreviousMongoGrammarWithMatchingGuids_ShouldBeUpdatedFrom
Assert.That(itemForTest, Is.Not.Null);
Assert.That(itemForTest.Abbreviation, Is.Not.EqualTo("Different abbreviation"));
Assert.That(itemForTest.Value, Is.Not.EqualTo("Different name"));
Assert.That(itemForTest.Key, Is.EqualTo("Different key")); // NOTE: Is.EqualTo, because keys shouldn't be updated
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/LfMerge.Core.Tests/Lcm/TransferMongoToLcmActionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ public void Action_ChangedWithSampleData_ShouldUpdatePictures()
Assert.That(entry.SensesOS[0].PicturesOS[1].PictureFileRA.InternalPath.ToString(),
Is.EqualTo(expectedExternalFileName));

LfMultiText expectedNewCaption = ConvertLcmToMongoLexicon.
ToMultiText(entry.SensesOS[0].PicturesOS[0].Caption, cache.ServiceLocator.WritingSystemManager);
LfMultiText expectedNewCaption = LfMultiText.FromLcmMultiString(
entry.SensesOS[0].PicturesOS[0].Caption, cache.ServiceLocator.WritingSystemFactory);
int expectedNumOfNewCaptions = expectedNewCaption.Count();
Assert.That(expectedNumOfNewCaptions, Is.EqualTo(2));
string expectedNewVernacularCaption = expectedNewCaption["qaa-x-kal"].Value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ private BsonDocument GetCustomFieldData(int hvo, int flid, string fieldSourceTyp
else
{
fieldValue = new BsonDocument("values", innerValues);
fieldGuid = new BsonArray(dataGuids.Select(guid => guid.ToString()));
fieldGuid = new BsonArray(dataGuids.Select(g => g.ToString()));
}
break;

Expand Down Expand Up @@ -489,9 +489,9 @@ private BsonValue GetCustomReferencedObject(int hvo, int flid,
servLoc.WritingSystemManager, LcmMetaData, cache.DefaultUserWs);
else if (referencedObject is ICmPossibility)
{
//return GetCustomListValues((ICmPossibility)referencedObject, flid);
string listCode = GetParentListCode(flid);
return new BsonString(listConverters[listCode].LfItemKeyString((ICmPossibility)referencedObject, _wsEn));
ICmPossibility poss = (ICmPossibility) referencedObject;
var abbreviation = ConvertLcmToMongoTsStrings.TextFromTsString(poss.Abbreviation.get_String(_wsEn), servLoc.WritingSystemFactory);
return new BsonString(abbreviation);
}
else
return null;
Expand Down
Loading